alibaba/COLA事件总线EventBus实现

很多时候我们会遇到这类场景,比如说“发生某件事情时”、“当什么产生变化时”、“如果什么状态变更时”,我们可以通过观察者模式来解耦,在领域驱动设计也称为领域事件。

下文分析 https://github.com/alibaba/COLA 的实现方式。

事件总线,以 EventBus#fireAll 方法为例,该方法会根据参数 EventI 获取具体的 EventHandler 并执行。EventHub 具体实现看下面
@Component
public class EventBus implements EventBusI{
    Logger logger = LoggerFactory.getLogger(EventBus.class);

    /**
     * 默认线程池
     *     如果处理器无定制线程池,则使用此默认
     */
    ExecutorService defaultExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 1,
                                   Runtime.getRuntime().availableProcessors() + 1,
                                   0L,TimeUnit.MILLISECONDS,
                           new LinkedBlockingQueue<Runnable>(1000),new ThreadFactoryBuilder().setNameFormat("event-bus-pool-%d").build());

    @Autowired
    private EventHub eventHub;

    @SuppressWarnings("unchecked")
    @Override
    public Response fire(EventI event) {
        // ...省略
    }

    @Override
    public void fireAll(EventI event){
        eventHub.getEventHandler(event.getClass()).stream().map(p->{
            Response response = null;
            try {
                response = p.execute(event);
            }catch (Exception exception) {
                response = handleException(p, response, exception);
            }
            return response;
        }).collect(Collectors.toList());
    }

    @Override
    public void asyncFire(EventI event){
        // ...省略
    }

    private Response handleException(EventHandlerI handler, Response response, Exception exception) {
        // ...省略
    }
}
事件控制中枢,EventHub#eventRepository 保存了具体 EventI 和 EventHandlerI 的对应关系
@Component
public class EventHub {
    @Getter
    @Setter
    private ListMultimap<Class, EventHandlerI> eventRepository = ArrayListMultimap.create();
    
    @Getter
    private Map<Class, Class> responseRepository = new HashMap<>();
    
    public List<EventHandlerI> getEventHandler(Class eventClass) {
        List<EventHandlerI> eventHandlerIList = findHandler(eventClass);
        if (eventHandlerIList == null || eventHandlerIList.size() == 0) {
            throw new ColaException(eventClass + "is not registered in eventHub, please register first");
        }
        return eventHandlerIList;
    }

    /**
     * 注册事件
     * @param eventClz
     * @param executor
     */
    public void register(Class<? extends EventI> eventClz, EventHandlerI executor){
        eventRepository.put(eventClz, executor);
    }

    private List<EventHandlerI> findHandler(Class<? extends EventI> eventClass){
        List<EventHandlerI> eventHandlerIList = null;
        Class cls = eventClass;
        eventHandlerIList = eventRepository.get(cls);
        return eventHandlerIList;
    }

}
接着看一下如何注册的,负责扫描在applicationContext.xml中配置的packages. 获取到CommandExecutors, intercepters, extensions, validators等交给各个注册器进行注册
public class Bootstrap {
    @Getter
    @Setter
    private List<String> packages;
    private ClassPathScanHandler handler;

    @Autowired
    private RegisterFactory registerFactory;


    public void init() {
        // scanConfiguredPackages 扫描各个 packages
        Set<Class<?>> classSet = scanConfiguredPackages();
        // 注册
        registerBeans(classSet);
    }

    /**
     * @param classSet
     */
    private void registerBeans(Set<Class<?>> classSet) {
        for (Class<?> targetClz : classSet) {
            //    调用工厂方法 getRegister
            //    public RegisterI getRegister(Class<?> targetClz) {
            //        ...省略代码,和下面的获取方式相同
            //        EventHandler eventHandlerAnn = targetClz.getDeclaredAnnotation(EventHandler.class);
            //        if (eventHandlerAnn != null) {
            //            eventRegister 是通过 spring 注入的单例
            //            return eventRegister;
            //        }
            //        return null;
            //    }
            RegisterI register = registerFactory.getRegister(targetClz);
            if (null != register) {
                register.doRegistration(targetClz);
            }
        }

    }

    /**
     * Scan the packages configured in Spring xml
     *
     * @return
     */
    private Set<Class<?>> scanConfiguredPackages() {
        if (packages == null) throw new ColaException("Command packages is not specified");

        String[] pkgs = new String[packages.size()];
        handler = new ClassPathScanHandler(packages.toArray(pkgs));

        Set<Class<?>> classSet = new TreeSet<>(new ClassNameComparator());
        for (String pakName : packages) {
            classSet.addAll(handler.getPackageAllClasses(pakName, true));
        }
        return classSet;
    }
}
以 EventRegister 为例
@Component
public class EventRegister implements RegisterI {

    @Autowired
    private EventHub eventHub;

    @Override
    public void doRegistration(Class<?> targetClz) {
        // 获取 EventI (也就是上述 EventHub#eventRepository 的 key)
        Class<? extends EventI> eventClz = getEventFromExecutor(targetClz);
        EventHandlerI executor = (EventHandlerI) ApplicationContextHelper.getBean(targetClz);
        eventHub.register(eventClz, executor);
    }
    
    /**
    * 获取方式:扫描 EventHandlerI 所有方法,判断是否是 execute 方法,如果是则获取该方法的入参作为 EventHub#eventRepository 的 key
    * @param eventExecutorClz
    * @return 
    */
    private Class<? extends EventI> getEventFromExecutor(Class<?> eventExecutorClz) {
        Method[] methods = eventExecutorClz.getDeclaredMethods();
        for (Method method : methods) {
            if (isExecuteMethod(method)){
                return checkAndGetEventParamType(method);
            }
        }
        throw new ColaException("Event param in " + eventExecutorClz + " " + ColaConstant.EXE_METHOD
                                 + "() is not detected");
    }
    
    // ...省略代码
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值