Spring|Spring 事件机制

Spring|Spring 事件机制
文章图片

概念 在一个完整的事件体系中、存在以下的角色

  1. 事件:描述发生了什么事情、比如说请求处理完成、Spring 容器刷新完毕
  2. 事件源:事件的产生者、任何一个事件都必须有一个事件源。比如请求处理完成的事件源就是 DispatcherServlet 、Spring 容器刷新完毕的事件源就是 ApplicationContext
  3. 事件广播器:事件和事件监听器的桥梁、负责把事件通知给事件监听器
  4. 事件监听器:监听事件的发生、可以在监听器中做一些处理
Spring 事件 Spring|Spring 事件机制
文章图片

我们常见的事件可能就是 ApplicationContextEvent 、它的子类 ContextRefreshedEvent 是我们常见的事件类型、在 Spring 将所有非延迟加载的 bean 实例化之后发布。
Spring|Spring 事件机制
文章图片

再来看看 Spring 事件的体系结构
Spring|Spring 事件机制
文章图片

Spring 监听器
Spring|Spring 事件机制
文章图片

【Spring|Spring 事件机制】事件广播器
Spring|Spring 事件机制
文章图片

Spring|Spring 事件机制
文章图片

ApplicationContext 对事件的支持
Spring|Spring 事件机制
文章图片

ApplicationEventPublisher 这个是 Spring 提供给用户使用的一个事件发布器啊、真正实现发布功能还是委托给上面的 ApplicationEventMulticaster 去实现的。
Spring 提供了 ApplicationEventPublisherAware 让用户可以去获取这个发布器进行事件发布。
使用方式
Spring 提供了两种方式
  1. 实现 ApplicationListener 接口
  2. 使用注解 @EventListener
注解的实现源码 我们直接看到 EventListenerMethodProcessor 该类实现了接口 SmartInitializingSingleton 接口、该接口会在 Spring 初始化完所有的非延迟加载的 bean 之后被调用。
public interface SmartInitializingSingleton {/** * Invoked right at the end of the singleton pre-instantiation phase, * with a guarantee that all regular singleton beans have been created * already. {@link ListableBeanFactory#getBeansOfType} calls within * this method won't trigger accidental side effects during bootstrap. * NOTE: This callback won't be triggered for singleton beans * lazily initialized on demand after {@link BeanFactory} bootstrap, * and not for any other bean scope either. Carefully use it for beans * with the intended bootstrap semantics only. */ void afterSingletonsInstantiated(); }

Spring|Spring 事件机制
文章图片

其实实现逻辑非常简单
for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { 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; } } }

找出所有被注解修饰的方法、然后分别创建一个对应的 ApplicationListener、收到事件后反射调用该方法。
public void processEvent(ApplicationEvent event) { Object[] args = resolveArguments(event); if (shouldHandle(event, args)) { Object result = doInvoke(args); if (result != null) { handleResult(result); } else { logger.trace("No result object given - no result to handle"); } } }

监听器调用的先后顺序
我们可以在 AbstractApplicationEventMulticaster#retrieveApplicationListeners 中看到是支持我们指定监听器的顺序的、Spring 很多涉及顺序的都可以使用
  1. 实现 Ordered 接口
  2. 实现 PriorityOrdered 接口
  3. 使用 @Ordered 接口
异步调用监听器
默认情况下、Spring 创建的事件广播器是采用同步方式调用通知监听器的、我们可以设置或者替换 Spring 默认的监听器来达到异步调用的目的、当然也可以扩展、根据事件的不同采用同步或者异步的方式、而不是单一的要么所有同步要么所有异步
@Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); for (ApplicationListener listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }

Spring refresh 之前回初始化事件传播器
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); if (logger.isTraceEnabled()) { logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isTraceEnabled()) { logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } }

替换原来的事件传播器
@Component("applicationEventMulticaster") public class TestEventMulticaster extends SimpleApplicationEventMulticaster { }

    推荐阅读