2016-06-22 6 views
1

Guava EventBus를 동기화하여 사용 중입니다. 구독자 중 하나가 예외를 throw하면 전체 트랜잭션을 롤백하는 방법은 무엇입니까? EventBus 가입자가 잡히지 않을 예외를 던지려면 어떻게해야합니까?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; 
    } 
} 

가입자 스레드 로컬 변수

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을 사용합니다.이 메서드는 호출 된 메서드가 예외를 throw하면 InvocationTargetException을 차례로 throw합니다. 당신은 또한 볼 수 있듯이

로 처리됩니다 (당신의 Exception 감싸됩니다) InvocationTargetException은 다음과 같습니다

상위 수준에서
} 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을 던지십시오. 이는 분명히 나쁜 습관입니다.

가입자가 Exception을 throw하는 경우 전체 트랜잭션을 어떻게 롤백 할 수 있습니까?

EventBus 예외 처리기는 com.google.common.eventbus.EventBus#handleSubscriberException 메서드를 호출하여 예외를 처리합니다.

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

따라서 예외 처리기에서 발생한 모든 예외는 도움이되지 않습니다.

  • 또는 수동으로이 흐름에 어떤 장소에서 롤백 전용으로 트랜잭션을 설정 (이 sooo를 나쁜) 당신의 가입자 방법에서

    1. 하나 던져 오류 : 두 가지 선택이있다. 나는 그런 것들을위한 최고의 장소가 명백하게 EventBus 예외 핸들러라고 생각한다.
  • 0

    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); 
        } 
    }