基于guava整合spring实现EventBus

原创
2018/07/04 10:27
阅读数 2.7W

为什么要用EventBus?

实现了进程内广播与监听,代码层实现了逻辑解耦。通常用于发短信、邮件、写日志、数据埋点等场景。

为什么要整合spring重新造轮子?

原因是直接使用EventBus监听的类是不被spring托管,也就是说 @Subscribe类是不能直接通过spring 注入bean。

代码实现:

欢迎访问 : https://github.com/awoter/fact-bus

/***
 ** 用于标记Event事件
 **/
public interface BaseEvent {

}
/***
 ** 所有Event处理类都要继承此Adapter类 实现process进行相关event处理
 **/
public abstract class EventAdapter<E extends BaseEvent> {

    private static final Logger logger = LoggerFactory.getLogger(EventAdapter.class);

    private static final String METHOD_NAME = "process";

    @Subscribe
    @SuppressWarnings("all")
    public void onEvent(BaseEvent event) {
    if (ReflectionUtils.findMethod(this.getClass(), METHOD_NAME, event.getClass()) != null) {
        try {
        if (!process((E)event)) {
            logger.warn("handle event {} fail", event.getClass());
        }
        } catch (Exception e) {
        logger.error(String.format("handle event %s exception", event.getClass()), e);
        }
    }
    }

    public abstract boolean process(E e);

}
/***
 ** EventBus处理类,主要用于注册或注销及发布相关事件
 */
public class EventBusFacade {

    private static final Logger logger = LoggerFactory.getLogger(EventBusFacade.class);

    private final static EventBus eventBus = new EventBus();

    public static void post(BaseEvent event) {
       execute(event);
    }


    public static void execute(BaseEvent event) {
       if(event == null){
           return ;
       }
       eventBus.post(event);
    }



    public static void register(EventAdapter<? extends BaseEvent> handler) {
       if(handler == null){
          return ;
       }
       eventBus.register(handler);
       logger.info("Registered eventAdapter class: {}", handler.getClass());
    }


    public static void unregister(EventAdapter<? extends BaseEvent> handler) {
       if(handler == null){
           return ;
       }
       eventBus.unregister(handler);
       logger.info("Unregisted eventAdapter class: {}", handler.getClass());
    }

}

三个类就完成核心的封装,下面通过什么办法可以实现自动注册及注销EventAdapter呢,请继续往下看:

@Configuration
@SuppressWarnings("all")
public class EventBusConfiguration implements InitializingBean, DisposableBean {

    @Autowired
    private ApplicationContext applicationContext;

    private Map<String, EventAdapter> beans = null;

    @Override
    public void afterPropertiesSet() throws Exception {

       beans = applicationContext.getBeansOfType(EventAdapter.class);
       if (beans != null) {
          for (EventAdapter eventAbstract : beans.values()) {
             EventBusFacade.register(eventAbstract);
          }
       }
    }

    @Override
    public void destroy() throws Exception {
       if (beans != null) {
           for (EventAdapter eventAbstract : beans.values()) {
              EventBusFacade.unregister(eventAbstract);
           }
       }
    }

}

OK,到这就已实现自动注册及注销 EventAdapter ,再加上下面这个激活注解就完美了。

@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(EventBusConfiguration.class)
@Documented
public @interface EnableEventBus {

}

到此,封装结束;

使用示例:

public class TestEvent implements BaseEvent{

    private String name;

    public TestEvent(){}

    public TestEvent(String a){
    this.name = a;
    }

    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }

}



@Component
public class TestEventHandler extends EventAdapter<TestEvent>{

    private static final Logger logger = LoggerFactory.getLogger(EventBusFacade.class);

    @Override
    public boolean process(TestEvent e) {

      logger.info("==================== 收到测试事件 ===================");

      return true;
    }

}


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/spring.xml")
public class TestLaunch {

    @Test
    public void testExecute() {

       EventBusFacade.execute(new TestEvent()); //发布事件

    }

}
展开阅读全文
打赏
0
31 收藏
分享
加载中
具体源码问题在这里:
private static ImmutableList<Method> getAnnotatedMethodsNotCached(Class<?> clazz) {
Set<? extends Class<?>> supertypes = TypeToken.of(clazz).getTypes().rawTypes();
Map<MethodIdentifier, Method> identifiers = Maps.newHashMap();
for (Class<?> supertype : supertypes) {
for (Method method : supertype.getDeclaredMethods()) {
if (method.isAnnotationPresent(Subscribe.class) && !method.isSynthetic()) {
// TODO(cgdecker): Should check for a generic parameter type and error out
Class<?>[] parameterTypes = method.getParameterTypes();
checkArgument(parameterTypes.length == 1,
"Method %s has @Subscribe annotation but has %s parameters."
+ "Subscriber methods must have exactly 1 parameter.",
method, parameterTypes.length);

MethodIdentifier ident = new MethodIdentifier(method);
if (!identifiers.containsKey(ident)) {
identifiers.put(ident, method);
2020/07/23 14:08
回复
举报
有bug,兄弟,继承EventAdapter 后,在订阅事件异步时间时,虽然最终执行了一个监听,但是在多个事件和监听下,会有多个事件进入队列
2020/07/22 18:52
回复
举报
更多评论
打赏
2 评论
31 收藏
0
分享
返回顶部
顶部