四、浅析Spring事件(源码分析)

浅析Spring事件

Spring事件主要有三部分组成,事件发布器、事件、事件监听器。本文将从以上几个方面简要分析一下Spring 事件的实现,Spring在事件上整体逻辑还是比较简单。

1. 如何使用?

Spring事件都有用过,所以就不单独说明如何使用,简单说明一下,本文使用到的例子。

java 复制代码
@Configuration
public class EventDemo {

   public static void main(String[] args) {

      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

      context.register(EventDemo.class);

      context.refresh();

      context.publishEvent("test");
      context.publishEvent(new PayloadApplicationEvent<Integer>(context, 12));
      context.publishEvent(new PayloadApplicationEvent<Integer>(context, 10));
      context.publishEvent(1.1);

      context.close();
   }

   @EventListener
   public void test(PayloadApplicationEvent<String> event) {

      String payload = event.getPayload();
      System.out.println(payload);
   }

   @EventListener(condition = "#root.args[0].payload == 12")
   public void testInteger(PayloadApplicationEvent<Integer> event) {

      System.out.println(event.getPayload());
   }

   @EventListener
   public void testDouble(PayloadApplicationEvent<Double> event) {
      System.out.println(event.getPayload());
   }
}

输出结果为:

bash 复制代码
test
12
1.1

2. 事件发布器

在ApplicationContext启动的流程中,会主动创建事件发布器。默认情况为SimpleApplicationEventMulticaster,ApplicationContext在此基础上作了封装,实际事件发布或者事件订阅,都是SimpleApplicationEventMulticaster在处理。而SimpleApplicationEventMulticaster也是Spring上唯一的ApplicationEventMulticaster接口实现类。

java 复制代码
//AbstractApplicationContext#initApplicationEventMulticaster
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() + "]");
      }
   }
}

事件发布,事件会上调用ApplicationEventMulticaster接口的multicastEvent方法。在SimpleApplicationEventMulticaster上的实现,可以看到,默认可以通过手动设置Executor,来实现异步调用监听器(在Listener不通过@Async注解的情况下)

java 复制代码
//SimpleApplicationEventMulticaster#multicastEvent
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);
      }
   }
}

默认情况下SimpleApplicationEventMulticaster的Executor为空,需要手动设置。

java 复制代码
//SimpleApplicationEventMulticaster#getTaskExecutor
protected Executor getTaskExecutor() {
   return this.taskExecutor;
}
java 复制代码
//SimpleApplicationEventMulticaster#setTaskExecutor
public void setTaskExecutor(@Nullable Executor taskExecutor) {
   this.taskExecutor = taskExecutor;
}

在调用Listener的时候,可以设置错误处理,单调用出错时,可以做相应逻辑

java 复制代码
//SimpleApplicationEventMulticaster#invokeListener
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
   ErrorHandler errorHandler = getErrorHandler();
   if (errorHandler != null) {
      try {
         doInvokeListener(listener, event);
      }
      catch (Throwable err) {
         errorHandler.handleError(err);
      }
   }
   else {
      doInvokeListener(listener, event);
   }
}

默认情况下SimpleApplicationEventMulticaster的ErrorHandler为空,需要手动设置。

java 复制代码
//SimpleApplicationEventMulticaster#getErrorHandler
protected ErrorHandler getErrorHandler() {
   return this.errorHandler;
}
java 复制代码
//SimpleApplicationEventMulticaster#setErrorHandler
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
   this.errorHandler = errorHandler;
}

在真正调用的时候,会调用ApplicationListener接口的onApplicationEvent方法。

java 复制代码
//SimpleApplicationEventMulticaster#doInvokeListener
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
   try {
      listener.onApplicationEvent(event);
   }
   catch (ClassCastException ex) {
      String msg = ex.getMessage();
      if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
        
      }
      else {
         throw ex;
      }
   }
}

3. 事件发布

以通过ApplicationContext发布事件为例,

java 复制代码
//AbstractApplicationContext#publishEvent
public void publishEvent(ApplicationEvent event) {
   publishEvent(event, null);
}

内部会调用publishEvent方法,带有ResolvableType。如果发送的时间不是ApplicationEvent类型,则会通过PayloadApplicationEvent进行包装;如果还在启动阶段,则会先加入早期事件列表;如果ApplicationContext还有父类,则父类也会发送事件。

java 复制代码
//AbstractApplicationContext#publishEvent
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
 
   ApplicationEvent applicationEvent;
   if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
   }else {
      //不是ApplicationEvent类型,会用PayloadApplicationEvent包装一层
      applicationEvent = new PayloadApplicationEvent<>(this, event);
      if (eventType == null) {
         eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
      }
   }

   // 如果还在启动阶段,那么就加入到早期事件
   if (this.earlyApplicationEvents != null) {
      this.earlyApplicationEvents.add(applicationEvent);
   }
   else {
      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
   }

   // 父类Context也会发送事件
   if (this.parent != null) {
      if (this.parent instanceof AbstractApplicationContext) {
         ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
      }
      else {
         this.parent.publishEvent(event);
      }
   }
}

在获取ApplicationEventMulticaster然后会调用multicastEvent的方法,在前面我们知道,默认的ApplicationEventMulticaster就是SimpleApplicationEventMulticaster。发送的逻辑也比较简单,就是获取跟事件类型匹配的ApplicationListener,匹配将通过事件的类型(匹配逻辑此处不展开),然后(可以异步调用)调用ApplicationListener的onApplicationEvent方法。

java 复制代码
//SimpleApplicationEventMulticaster#multicastEvent
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);
      }
   }
}

4. 事件订阅

那么ApplicationListener怎么来呢,需要通过事件的订阅,有两种方式处理。

4.1 实现ApplicationListener接口

在ApplicationContext启动的流程中,会添加一个BeanPostProcessor到BeanFactory中。通过BeanPostProcessor扩展接口,处理ApplicationListener接口的注册

java 复制代码
//AbstractApplicationContext#prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
}

在ApplicationListenerDetector的postProcessAfterInitialization方法,会判断bean是否实习ApplicationListener,并且如果是单例的话,会通过通过ApplicationContext添加ApplicationListener,完成接口的订阅

java 复制代码
//ApplicationListenerDetector#BeanPostProcessor
public Object postProcessAfterInitialization(Object bean, String beanName) {
	if (bean instanceof ApplicationListener) {
		// potentially not detected as a listener by getBeanNamesForType retrieval
		Boolean flag = this.singletonNames.get(beanName);
		if (Boolean.TRUE.equals(flag)) {
			// singleton bean (top-level or inner): register on the fly
			this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
		}
	}
	return bean;
}

在AbstractApplicationContext内部如果applicationEventMulticaster不为空,则通过applicationEventMulticaster增加监听器,同时也将添加到applicationListeners列表,此目的之一,是为了防止ApplicationEventMulticaster还没有初始化之前就调用了addApplicationListener接口。

java 复制代码
//AbstractApplicationContext#addApplicationListener
public void addApplicationListener(ApplicationListener<?> listener) {
   Assert.notNull(listener, "ApplicationListener must not be null");
   if (this.applicationEventMulticaster != null) {
      this.applicationEventMulticaster.addApplicationListener(listener);
   }
   this.applicationListeners.add(listener);
}

因此在Spring 启动流程中,在registerListeners步骤中(在初始化ApplicationEventMulticaster之后),会将applicationListeners列表的监听器,添加到ApplicationEventMulticaster中。

java 复制代码
//AbstractApplicationContext#registerListeners
protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }
   //...
}

4.2 @EventListener注解

在AnnotatedBeanDefinitionReader对象创建的时候,会注册两个BeanDefinition(作为内部类)到容器中:EventListenerMethodProcessor和DefaultEventListenerFactory

java 复制代码
//AnnotatedBeanDefinitionReader
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
  
   AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
java 复制代码
//AnnotationConfigUtils#registerAnnotationConfigProcessors
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {
      	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}
      
 }

在ApplicationContext启动的流程中,在预创建Bean实例的时候,会调用SmartInitializingSingleton的afterSingletonsInstantiated方法

java 复制代码
public void preInstantiateSingletons() throws BeansException {
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			smartSingleton.afterSingletonsInstantiated();
		}
	}
}

EventListenerMethodProcessor实现了SmartInitializingSingleton接口,因此@EventListener注解封装成ApplicationListener接口的逻辑,就会在该类中实现。

java 复制代码
//EventListenerMethodProcessor#afterSingletonsInstantiated
public void afterSingletonsInstantiated() {

   //...
   processBean(beanName, type);
   //...
}

首先会获取方法和EventListener注解的映射关系

java 复制代码
//EventListenerMethodProcessor#processBean
Map<Method, EventListener> annotatedMethods = null;
try {
   annotatedMethods = MethodIntrospector.selectMethods(targetType,
         (MethodIntrospector.MetadataLookup<EventListener>) method ->
               AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}

然后会遍历方法和EventListener,然后会会循环处理EventListenerFactory,而从前面我们得知,一般情况下EventListenerFactory只有,DefaultEventListenerFactory。而DefaultEventListenerFactory的supportsMethod默认都是true,所以会调用DefaultEventListenerFactory的createApplicationListener方法。

java 复制代码
//EventListenerMethodProcessor#processBean
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;
      }
   }
}

其中默认返回的默认是ApplicationListenerMethodAdapter方法,还会触发init方法调用(判断ApplicationListenerMethodAdapter后调init,感觉有点硬编码),最后会加入到ApplicationContext的事件监听器列表中。

java 复制代码
//DefaultEventListenerFactory#createApplicationListener
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
   return new ApplicationListenerMethodAdapter(beanName, type, method);
}

ApplicationListenerMethodAdapter的init方法也很简单,就是存储了一下成员变量

java 复制代码
//ApplicationListenerMethodAdapter#init
void init(ApplicationContext applicationContext, EventExpressionEvaluator evaluator) {
   this.applicationContext = applicationContext;
   this.evaluator = evaluator;
}

4.3 ApplicationListenerMethodAdapter处理

ApplicationListenerMethodAdapter肯定是实现了ApplicationListener接口的,那么看下onApplicationEvent方法中,如何代理方法操作。

java 复制代码
//ApplicationListenerMethodAdapter#onApplicationEvent
public void onApplicationEvent(ApplicationEvent event) {
   processEvent(event);
}

首先会解析参数,然后判断是否要调用,是的话会执行调用,如果有返回结果则还会处理返回结果。

java 复制代码
//ApplicationListenerMethodAdapter#processEvent
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");
      }
   }
}

1)解析参数,主要是获取参数,以便后面做表达式的判断。这里对于PayloadApplicationEvent的判断有点奇怪,如果事件不是ApplicationEvent的子类但是对象又是PayloadApplicationEvent,我们知道PayloadApplicationEvent是继承了ApplicationEvent,所以这里的判断不知道什么场景下才会使用。

java 复制代码
//ApplicationListenerMethodAdapter#resolveArguments
protected Object[] resolveArguments(ApplicationEvent event) {
   ResolvableType declaredEventType = getResolvableType(event);
   if (declaredEventType == null) {
      return null;
   }
   if (this.method.getParameterCount() == 0) {
      return new Object[0];
   }
   Class<?> declaredEventClass = declaredEventType.toClass();
   if (!ApplicationEvent.class.isAssignableFrom(declaredEventClass) &&
         event instanceof PayloadApplicationEvent) {
      Object payload = ((PayloadApplicationEvent) event).getPayload();
      if (declaredEventClass.isInstance(payload)) {
         return new Object[] {payload};
      }
   }
   return new Object[] {event};
}

2)判断是否能调用,@EventListener注解是可以写condition参数的,里面会调用expression表达式,进行判断。

java 复制代码
//ApplicationListenerMethodAdapter#shouldHandle
private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
   if (args == null) {
      return false;
   }
   String condition = getCondition();
   if (StringUtils.hasText(condition)) {
      Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
      return this.evaluator.condition(
            condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);
   }
   return true;
}

3)确认需要调用后,会通过反射的方式,调用方法。

java 复制代码
//ApplicationListenerMethodAdapter#doInvoke
protected Object doInvoke(Object... args) {
   Object bean = getTargetBean();
   ReflectionUtils.makeAccessible(this.method);
   try {
      return this.method.invoke(bean, args);
   }
}

4)最后会处理接口,如果事件监听器返回了对象,那么会把这个对象再次通过事件发送出去。

java 复制代码
//ApplicationListenerMethodAdapter#handleResult
protected void handleResult(Object result) {
   if (result.getClass().isArray()) {
      Object[] events = ObjectUtils.toObjectArray(result);
      for (Object event : events) {
         publishEvent(event);
      }
   }
   else if (result instanceof Collection<?>) {
      Collection<?> events = (Collection<?>) result;
      for (Object event : events) {
         publishEvent(event);
      }
   }
   else {
      publishEvent(result);
   }
}
java 复制代码
//ApplicationListenerMethodAdapter#publishEvent
private void publishEvent(@Nullable Object event) {
   if (event != null) {
      this.applicationContext.publishEvent(event);
   }
}

这个特性不知道用不好可能会出现死循环,例如以下例子,会导致循环发布事件。

发布事件

arduino 复制代码
context.publishEvent(new PayloadApplicationEvent<String>(this,"111"));

监听事件

java 复制代码
@EventListener
public String test(PayloadApplicationEvent<String> event){
   String payload = event.getPayload();
   System.out.println(payload);
   return "123456";
}

5. 参考资料

  1. Spring 5.1.x源码
相关推荐
落落落sss16 分钟前
MQ集群
java·服务器·开发语言·后端·elasticsearch·adb·ruby
我救我自己16 分钟前
UE5运行时创建slate窗口
java·服务器·ue5
2401_8532757336 分钟前
ArrayList 源码分析
java·开发语言
爪哇学长41 分钟前
SQL 注入详解:原理、危害与防范措施
xml·java·数据库·sql·oracle
MoFe11 小时前
【.net core】【sqlsugar】字符串拼接+内容去重
java·开发语言·.netcore
_江南一点雨1 小时前
SpringBoot 3.3.5 试用CRaC,启动速度提升3到10倍
java·spring boot·后端
深情废杨杨1 小时前
后端-实现excel的导出功能(超详细讲解)
java·spring boot·excel
智汇探长1 小时前
EasyExcel自定义设置Excel表格宽高
java·excel·easyexcel
酸奶代码1 小时前
Spring AOP技术
java·后端·spring
代码小鑫2 小时前
A034-基于Spring Boot的供应商管理系统的设计与实现
java·开发语言·spring boot·后端·spring·毕业设计