2016-06-22 6 views
1

Я использую Guava EventBus в синхронизации. Как я могу отменить полную транзакцию, если какой-либо из подписчиков выбрал исключение? Как я могу выбросить исключение, которое не будет захвачено подписчиком EventBus?Throw исключение из Guava EventBus подписчик

+0

I Если бы это было возможно, удивляйтесь. –

+0

Если это невозможно, разве это не ограничение шины событий, что она не может быть транзакционной? – Shikhar

+0

Да. Конечно. –

ответ

0

Я решил его с помощью java.lang.ThreadLocal переменных через издатель и абонент.

Издатель должен быть обернут в классе, который читает нить локальное исключение и бросает его нужно завернуть в классе

public void publish(Event event) { 
    eventBus.post(event); 
    if(threadLocalException != null) { 
    Store threadLocalException in some variable say e 
    Clear threadLocalException variable 
    throw e; 
    } 
} 

Subscriber установить исключение в потоке локальной переменной

public abstract class EventSubscriber<T extends Event> { 

    @Subscribe 
    public void invoke(T event) { 
    try { 
     handle(event); 
    } catch (Exception e) { 
     Set thread local variable to e 
    } 
    } 

    protected abstract void handle(T event); 

} 
1

Все, что вам нужно сделать, это посмотреть исходный код класса Guava EventBus.

Начнем с конца:

Как я могу выбросить исключение, которое не будет перехватывается EventBus подписчика?

Методы подписчиков вызываются последовательно, один за другим, методом com.google.common.eventbus.Dispatcher#dispatch. Чтобы вызвать методы ваших подписчиков, EventBus использует метод отражения Method#invoke, который, в свою очередь, выдает InvocationTargetException, если вызываемый метод выдает исключение.

Как вы можете видеть, InvocationTargetException (который будет обернут вокруг Exception) обрабатывается следующим образом:

} catch (InvocationTargetException e) { 
    if (e.getCause() instanceof Error) { 
    throw (Error) e.getCause(); 
    } 
    throw e; 
} 

на верхнем уровне, исключение обрабатывается так:

try { 
    invokeSubscriberMethod(event); 
} catch (InvocationTargetException e) { 
    bus.handleSubscriberException(e.getCause(), context(event)); 
} 

TL; DR

Таким образом, единственный способ пропустить EventBus обработчик исключений заключается в том, чтобы бросить не Exception, но Error в вашем подписном методе - что, безусловно, является плохой практикой.

Как отменить полную транзакцию, если какой-либо из абонентов выбрасывает исключение?

EventBus исключение обработчик обрабатывает исключения по телефону com.google.common.eventbus.EventBus#handleSubscriberException способ. Это выглядит так:

try { 
    exceptionHandler.handleException(e, context); 
} catch (Throwable e2) { 
    // logging 
} 

Таким образом, любые исключения, брошенные из обработчика исключений, не помогут. У вас есть два варианта:

  1. Либо бросок ошибки от вашего метода абонента (это ооочень плохо)
  2. Или вручную установить транзакцию как откат только из любого места в этом потоке. Я думаю, что лучшим местом для таких вещей является, очевидно, EventBus обработчик исключений.
0

Наследовать EventBus и создать собственный EventBus, который будет генерировать исключение. Пакет должен быть com.google.common.eventbus для handleSubscriberException является внутренним методом.

package com.google.common.eventbus; 

import com.google.common.util.concurrent.MoreExecutors; 

/** 
* A eventbus wihch will throw exceptions during event handle process. 
* @author ytm 
* 
*/ 
public class ErrorThrowEventBus extends EventBus { 

    /** 
    * Creates a new EventBus with the given {@code identifier}. 
    * 
    * @param identifier a brief name for this bus, for logging purposes. Should be a valid Java 
    *  identifier. 
    */ 
    public ErrorThrowEventBus(String identifier) { 
     super(
      identifier, 
      MoreExecutors.directExecutor(), 
      Dispatcher.perThreadDispatchQueue(), 
      LoggingHandler.INSTANCE); 
    } 

    /** 
    * Creates a new EventBus with the given {@link SubscriberExceptionHandler}. 
    * 
    * @param exceptionHandler Handler for subscriber exceptions. 
    * @since 16.0 
    */ 
    public ErrorThrowEventBus(SubscriberExceptionHandler exceptionHandler) { 
     super(
      "default", 
      MoreExecutors.directExecutor(), 
      Dispatcher.perThreadDispatchQueue(), 
      exceptionHandler); 
    } 

    /** 
    * Just throw a EventHandleException if there's any exception. 
    * @param e 
    * @param context 
    * @throws EventHandleException 
    */ 
    @Override 
    void handleSubscriberException(Throwable e, SubscriberExceptionContext context) throws EventHandleException { 
     throw new EventHandleException(e); 
    } 
}