Google Guava EventBus 和事件处理程序中的异常

Google Guava EventBus and Exceptions in Event Handlers

Guava EventBus 文档说 "handlers should not, in general, throw. If they do, the EventBus will catch and log the exception. This is rarely the right solution for error handling and should not be relied upon; it is intended solely to help find problems during development."

如果您知道可能会发生某些异常,您可以向 EventBus 注册一个 SubscriberExceptionHandler 并使用它来处理这些异常。

但是如果发生未处理的异常会怎样?通常,我想要 "bubble up" 调用链的未处理异常。使用 SubscriberExceptionHandler 时,我可以访问在事件处理程序中抛出的原始异常,我只想重新抛出它。但是我想不通。

那么,无论是否使用 SubscriberExceptionHandler,如何确保事件处理程序中的意外异常不是 "swallowed"?

如有任何帮助,我们将不胜感激。

如果你想处理未经检查的异常,你可以像这样实现 SubscriberExceptionHandler 的方法:

public void handleException(Throwable exception, SubscriberExceptionContext context) {
    // Check if the exception is of some type you wish to be rethrown, and rethrow it.
    // Here I'll assume you'd like to rethrow RuntimeExceptions instead of 'consuming' them.
    if (exception instanceof RuntimeException) {
        throw (RuntimeException) exception;
    }

    // If the exception is OK to be handled here, do some stuff with it, e.g. log it.
    ...
}

创建 class 实现 SubscriberExceptionHandler 接口后,您可以将其实例传递给 EventBus 的构造函数:

EventBus eventBus = new EventBus(new MySubscriberExceptionHandler());

完成后,eventBus 将使用您的异常处理程序,让 RuntimeExceptions 冒泡。

Guava 不会让异常冒泡。它被迫在 exceptionHandler 内部停止。请参阅下面的源代码。

      /**
       * Handles the given exception thrown by a subscriber with the given context.
       */
      void handleSubscriberException(Throwable e, SubscriberExceptionContext context) {
        checkNotNull(e);
        checkNotNull(context);
        try {
          exceptionHandler.handleException(e, context);
        } catch (Throwable e2) {
          // if the handler threw an exception... well, just log it
          logger.log(
              Level.SEVERE,
              String.format(Locale.ROOT, "Exception %s thrown while handling exception: %s", e2, e),
              e2);
        }
      }

我 post 关于 github 的问题。您可以继承 EventBus 并编写自己的异常处理逻辑。

package com.google.common.eventbus;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionContext;

/**
 * A eventbus wihch will throw exceptions during event handle process.
 * We think this behaviour is better.
 * @author ytm
 *
 */
public class BetterEventBus extends EventBus {

    public BetterEventBus() {}

    /**
     * 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 BetterEventBus(String identifier) {
        super(identifier);
    }

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