Spring 事件驱动简介

432 阅读4分钟

背景

随着业务越来越复杂,我们的项目开始采用 DDD 的架构方案,其中 DDD 的领域事件采用 Spring Event 实现,实现起来超级简单。

Spring Event 基本用法

Spring Event 的三个基本概念:

  • 事件:  定义事件,继承 ApplicationEvent 实现一个事件类。
  • 事件监听器:监听并处理事件,通过实现 ApplicationListener 或是在处理方法上使用 @EventListener 注解实现。
  • 事件发布器:发布事件,使用 ApplicationEventPublisher.publishEvent 发布事件。
// 自定义事件
public class TestEvent extends ApplicationEvent {
    public TestEvent(Object source) {
        super(source);
    }
}

// 自定义监听器
@Component
public class TestListener implements ApplicationListener<TestEvent> {
    @Override
    public void onApplicationEvent(TestEvent event) {
        System.out.println(event);
    }
}

// 发布事件
public void test() {
   ApplicationEventPublisher context = new AnnotationConfigApplicationContext();
   context.publishEvent(new TestEvent("发布自定义事件"));
}

原理

事件发布

// AbstractApplicationContext 中实现了事件发布的逻辑
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        // 获取事件派发器,派发事件给所有的监听器
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }
}

// 派发事件
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 如果有设置 Executor 则使用 Executor 异步执行,否则同步执行
    Executor executor = getTaskExecutor();
    // 获取所有的监听器,遍历监听器执行回调
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

// 回调
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
    }
}

1、获取事件派发器 getApplicationEventMulticaster()。 事件派发器在容器初始化时创建,后面还会提到。

2、获取 Executor,如果配置了 Executor,则使用 Executor 进行异步回调。

3、获取所有的监听器,遍历监听器,调用 onApplicationEvent() 回调。

获取所有 ApplicationListener 逻辑,在事件派发器中定义了一个内部类 ListenerRetriever用于缓存所有的监听器。

private class ListenerRetriever {
		public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
		// 缓存 beanName,用于原型模式,每次调用创建新的 bean 
		public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
}
private Collection<ApplicationListener<?>> retrieveApplicationListeners() {

  List<ApplicationListener<?>> allListeners = new ArrayList<>();
  Set<ApplicationListener<?>> listeners;
  Set<String> listenerBeans;
  synchronized (this.retrievalMutex) {
    listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
    listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
  }
  // 将所有的 listener 加入返回结果中
  for (ApplicationListener<?> listener : listeners) {
    if (supportsEvent(listener, eventType, sourceType)) {
      if (retriever != null) {
        retriever.applicationListeners.add(listener);
      }
      allListeners.add(listener);
    }
  }
  if (!listenerBeans.isEmpty()) {
    BeanFactory beanFactory = getBeanFactory();
    for (String listenerBeanName : listenerBeans) {
      try {
        Class<?> listenerType = beanFactory.getType(listenerBeanName);
        if (listenerType == null || supportsEvent(listenerType, eventType)) {
          // 通过 beanName 和 type 获取 bean 的实例
          ApplicationListener<?> listener =
            beanFactory.getBean(listenerBeanName, ApplicationListener.class);
          if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
              if (beanFactory.isSingleton(listenerBeanName)) {
                // 如果是单例模式加入到 retriever.applicationListeners 中
                retriever.applicationListeners.add(listener);
              }
              else {
                retriever.applicationListenerBeans.add(listenerBeanName);
              }
            }
            allListeners.add(listener);
          }
        }
      }
      catch (NoSuchBeanDefinitionException ex) {
      }
    }
  }
  // 通过 order 进行排序
  AnnotationAwareOrderComparator.sort(allListeners);
  if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
    retriever.applicationListeners.clear();
    retriever.applicationListeners.addAll(allListeners);
  }
  return allListeners;
}

1、在派发器的 retriever 中保存了所有的监听器 bean 实例和 beanName。(在容器初始化的时候保存beanName)

2、首先将所有的 bean 实例加入返回列表中,在遍历 beanName 从 BeanFactory 中获取 bean 的实例加入到返回列表中。对于单例模式的 bean 在加入到监听器列表中。

3、通过 @Order 注解排序

初始化事件监听器和事件派发器

// 启动 spring 容器时通过refresh 方法刷新容器
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);

        try {
            postProcessBeanFactory(beanFactory);

            invokeBeanFactoryPostProcessors(beanFactory);

            registerBeanPostProcessors(beanFactory);

            initMessageSource();

            // 初始化事件派发器
            initApplicationEventMulticaster();

            onRefresh();

            // 注册监听器
            registerListeners();

            finishBeanFactoryInitialization(beanFactory);

            finishRefresh();
        }
    }
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        // 从容器中获取派发器
        this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    }
    else {
        // 如果容器中没有则创建 SimpleApplicationEventMulticaster 派发器加入到容器中
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
}

1、初始化派发器的逻辑非常简单,先从容器中获取 beanName 为 applicationEventMulticaster 的 bean 做为派发器,如果没有则创建 SimpleApplicationEventMulticaster 做为派发器。

protected void registerListeners() {
    // 首先注册指定监听器
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 获取说有的监听器name,加入到派发器中
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }
}

1、注册监听器的逻辑也很简单,获取所有的 ApplicationListener 的 beanName,加入到派发器中。

@EventListener 注解

Spring 中提到注解就离不开 Processor 了,EventListener 注解也不例外,通过 EventListenerMethodProcessor 实现监听器的注册

public class EventListenerMethodProcessor
	implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
}

public interface SmartInitializingSingleton {
	void afterSingletonsInstantiated();
}

1、EventListenerMethodProcessor 实现了 SmartInitializingSingleton,SmartInitializingSingleton 这个接口在会在 Spring 容器实例化所有的单例对象后进行回调。

public void afterSingletonsInstantiated() {
    ConfigurableListableBeanFactory beanFactory = this.beanFactory;
    // 获取所有的 beanName
    String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
    for (String beanName : beanNames) {
        Class<?> type = null;
        try {
            // 获取 bean 的 class 类型
            type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
        }
        if (type != null) {
            try {
                // 实例化 bean
                processBean(beanName, type);
            }
        }
    }
}

private void processBean(final String beanName, final Class<?> targetType) {
    if (!this.nonAnnotatedClasses.contains(targetType) &&
        !targetType.getName().startsWith("java") &&
        !isSpringContainerClass(targetType)) {

        Map<Method, EventListener> annotatedMethods = null;
        try {
            // 反射获取 EventListener 注解的方法
            annotatedMethods = MethodIntrospector.selectMethods(targetType,
                                                                (MethodIntrospector.MetadataLookup<EventListener>) method ->
                                                                AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
        }

        if (CollectionUtils.isEmpty(annotatedMethods)) {
            this.nonAnnotatedClasses.add(targetType);
        }
        else {
            ConfigurableApplicationContext context = this.applicationContext;
            Assert.state(context != null, "No ApplicationContext set");
            List<EventListenerFactory> factories = this.eventListenerFactories;
            Assert.state(factories != null, "EventListenerFactory List not initialized");
            for (Method method : annotatedMethods.keySet()) {
                for (EventListenerFactory factory : factories) {
                    if (factory.supportsMethod(method)) {
                        // 校验该方法不是 private、不是 static,且是被代理的方法
                        Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                        // 创建监听器
                        ApplicationListener<?> applicationListener =
                            factory.createApplicationListener(beanName, targetType, methodToUse);
                        // 初始化监听器
                        if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                            ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                        }
                        context.addApplicationListener(applicationListener);
                        break;
                    }
                }
            }
        }
    }
}

1、@EventListener 通过 EventListenerMethodProcessor 实现监听器的创建和注册,EventListenerMethodProcessor 实现了 SmartInitializingSingleton 接口,在单例对象实例化后回调。

2、获取容器中所有的 bean 并遍历。

3、获取 bean 中带有 @EventListener 注解的方法。

4、校验方法,不是 private、static,且是被代理的,然后创建监听器并初始化。

5、加入到容器中。

总结

Spring Event 使用起来非常简单,很适合做为领域事件的实现方案。Spring Event 中通过继承 ApplicationEvent 定义一个事件,实现 ApplicationListener 或者使用 @EventListener 注解监听并处理事件,在通过 ApplicationEventPublisher 发布事件。Spring Event 实现原理在 Spring 容器刷新时先初始化派发器,然后注册所有的 ApplicationListener,最后通过 EventListenerMethodProcessor 注册带有 @EventListener 注解的方法。