我正在使用Guava EventBus同步。如果任何订阅者抛出异常,我该如何回滚整个事务?如何抛出一个不会被EventBus订阅者捕获的异常?
答案 0 :(得分: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
}
因此,从异常处理程序抛出的任何异常都无济于事。你有两个选择:
EventBus
异常处理程序。答案 1 :(得分:0)
继承EventBus并创建自己的eventBus,它会抛出异常。 软件包必须是com.google.common.eventbus for 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);
}
}
答案 2 :(得分:0)
我在发布商和订阅者之间使用java.lang.ThreadLocal
变量解决了这个问题。
Publisher需要包装在一个读取线程局部异常并抛出它的类中
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);
}