Spring事件监听流程分析【源码浅析】

本文深入解析Spring框架中事件监听机制的实现,从@EventListener注解的使用,到事件注册及监听流程的源码分析,全面阐述Spring如何通过观察者模式进行事件的发布与订阅。

一、简介

  • Spring早期是通过实现ApplicationListener接口来定义监听事件,在spring4.2的时候开始我们可以通过@EventListener注解来定义监听事件,ApplicationListener接口定义如下:
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
	/**
	 * 处理Spring监听事件,监听 ApplicationEvent 及其下面的子事件
	 * 这里的ApplicationListener接口相当于观察者模式中的观察者Obverse接口,
	 * 且此处使用的是观察者模式的“推-拉”模型中的“拉”模型, 主题对象在通知观察者
	 * 的时候,只传递少量信息。如果观察者需要更具体的信息, 由观察者主动到主题对
	 * 象中获取,相当于是观察者从主题对象中拉数据。一般这种 模型的实现中,会把主
	 * 题对 象自身通过update()方法传递给观察者,这样在观察 者需要获取数据的时候,
	 * 就可以通过这个引用来获取了。
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);
}
  • Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式(拉模型);为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
  • 比如在我们的系统中,我们需要记录某一些比较重要方法的调用日志,我们就可以通过自定义注解+实现自定义监听事件即可。
  • 本篇文章我们通过@EventListener注解来分析Spring的事件注册及监听流程

二、使用@EventListener注解

  1. 建立事件对象,当调用publishEvent方法是会通过这个bean对象找对应事件的监听。
package com.asiainfo.gridtask.event;

import com.asiainfo.gridtask.entity.log.SysLog;
import org.springframework.context.ApplicationEvent;

/**
 * 系统日志事件,ApplicationEvent相当于观察者模式中的Subject主题对象,Spring容器
 * 发布监听事件后,
 * @author Jack.Cheng
 * @date 2020/1/7 15:04
 **/
public class SysLogEvent extends ApplicationEvent {

    public SysLogEvent(SysLog sysLog) {
        super(sysLog);
    }
}
  • 看一看SysLogEvent类的继承图,SysLogEvent继承至ApplicationEvent,ApplicationEvent 继承至EventObject,EventObject对象中定义了一个Object类型的source变量用于存放事件的消息。
    在这里插入图片描述
  • 新增对应的监听类
package com.asiainfo.gridtask.event;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.asiainfo.gridtask.common.constant.CommonConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @author Jack.Cheng
 * @date 2020/1/7 15:08
 **/
@Slf4j
@Component
public class SysLogListener {

    @EventListener(SysLogEvent.class)
    public void saveSysLog(SysLogEvent event) {
        log.info("收到调用日志信息:info:{}" , JSON.toJSONString(event));
    }
}

  • 建立对应的测试类
package com.asiainfo.gridtask.controller;

import com.asiainfo.gridtask.entity.log.SysLog;
import com.asiainfo.gridtask.event.SysLogEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Jack.Cheng
 * @date 2020/4/7 16:34
 **/
@RestController
public class TestController {

    @Autowired
    private ApplicationContext applicationContext;

    @GetMapping("testEvent.do")
    public void testEvent(){
        SysLog sysLog = new SysLog();
        sysLog.setLogId("123456789")
              .setStaffCode("jack")
              .setPhoneNo("13378224441");
        applicationContext.publishEvent(new SysLogEvent(sysLog));
    }
}

  • 调用Restful接口后结果如下:
    在这里插入图片描述

三、源码解析

  • AnnotationConfigUtils#registerAnnotationConfigProcessors注册了EventListenerMethodProcessor 的BeanDefinition信息, 初始化SpringIOC容器的时候会将EventListenerMethodProcessor注册到容器中。
  • AnnotationConfigUtils是在AnnotationConfigServletWebServerApplicationContext构造方法里被加载。AnnotationConfigServletWebServerApplicationContext,他是spring boot启动入口的重要类(我这里用的是spring boot所以是这个类),可以相当于用xml的ClassPathXmlApplicationContext。
AnnotationConfigUtils类
	/**
	 * 内部管理@EventListener注解处理器的bean名称
	 * The bean name of the internally managed @EventListener annotation processor.
	 */
	public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
			"org.springframework.context.event.internalEventListenerProcessor";

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		...........省略...............
		
		// 注册EventListenerMethodProcessor对象
		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));
		}

		return beanDefs;
	}
  • 注册的EventListenerMethodProcessor对象会在初始化非懒加载对象的时候执行它的afterSingletonsInstantiated方法。这里通过AbstractApplicationContext类的refresh() 方法中的 finishBeanFactoryInitialization(beanFactory) 去做初始化。
  • AbstractApplicationContext#refresh()
public void refresh() throws BeansException, IllegalStateException {

   synchronized (this.startupShutdownMonitor) {
      // 记录容器的启动时间、标记“已启动”状态、检查环境变量
      prepareRefresh();
      // 初始化BeanFactory容器(DefaultListableBeanFactory)、注册BeanDefinition
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      prepareBeanFactory(beanFactory);
      try {
         // 扩展点,具体逻辑由子类去实现
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);
         // 注册 BeanPostProcessor 的实现类
         registerBeanPostProcessors(beanFactory);
         // 初始化MessageSource
         initMessageSource();
         // 注册Spring事件派发多播器
         initApplicationEventMulticaster();
         // 扩展点,交由子类实现
         onRefresh();
         // 注册事件监听器
         registerListeners();
         // 初始化所有的 singleton beans
         finishBeanFactoryInitialization(beanFactory);
         // 广播事件
         finishRefresh();
      }catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }
         // 销毁已经初始化的的Bean
         destroyBeans();
         // 设置 'active' 状态
         cancelRefresh(ex);
         throw ex;
      }finally {
         // 清除缓存
         resetCommonCaches();
      }
   }
}
  • 这里我们重点关注refresh()#finishBeanFactoryInitialization(beanFactory)#preInstantiateSingletons() 方法
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

		// 初始化非懒加载对象
		beanFactory.preInstantiateSingletons();
	}
  • DefaultListableBeanFactory#preInstantiateSingletons()
	@Override
	public void preInstantiateSingletons() throws BeansException {
		..........省略非必要代码...........
		// 将注册的beanDefinition类信息封装到集合中
		List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
		..........省略非必要代码...........
		// 触发所有适用bean的初始化后回调 主要是afterSingletonsInstantiated方法
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
	        /**
	         * 处理SmartInitializingSingleton的实现类,调用其afterSingletonsInstantiated()方法,该方法
	         * 会将带有EventListener注解的方法包装为ApplicationListenerMethodAdapter类,Spring容器发布
	         * 事件后将通过多播器触发调用这个类的onApplicationEvent(ApplicationEvent event)方法,这个方法
	         * 最终会通过反射的方式对应的调用我们加了EventListener注解的方法,最终完成事件的发布调用流程
	         */
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					// 调用afterSingletonsInstantiated方法(EventListenerMethodProcessor类)
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

  • EventListenerMethodProcessor类图如下,这里可以看到其实现了SmartInitializingSingleton接口
    在这里插入图片描述
  • EventListenerMethodProcessor#afterSingletonsInstantiated,敲黑板,这里开始注册带有@EventListener注解的方法了
	@Override
	public void afterSingletonsInstantiated() {
		// 获取EventListenerFactory工厂类
		ConfigurableListableBeanFactory beanFactory = this.beanFactory;
		Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
		String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
		for (String beanName : beanNames) {
			if (!ScopedProxyUtils.isScopedTarget(beanName)) {
				Class<?> type = null;
				try {
					type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
				}
				catch (Throwable ex) {
					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				if (type != null) {
					if (ScopedObject.class.isAssignableFrom(type)) {
						try {
							Class<?> targetClass = AutoProxyUtils.determineTargetClass(
									beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
							if (targetClass != null) {
								type = targetClass;
							}
						}
						catch (Throwable ex) {
							// An invalid scoped proxy arrangement - let's ignore it.
							if (logger.isDebugEnabled()) {
								logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
							}
						}
					}
					try {
						// 重点是这个方法处理Bean
						processBean(beanName, type);
					}
					catch (Throwable ex) {
						throw new BeanInitializationException("Failed to process @EventListener " +
								"annotation on bean with name '" + beanName + "'", ex);
					}
				}
			}
		}
	}
  • EventListenerMethodProcessor#processBean,这里会将带有EventListener注解的方法包装为ApplicationListenerMethodAdapter类,Spring容器在发布事件后会通过多播器触发调用这个类的onApplicationEvent(ApplicationEvent event)方法,这个方法最终会通过反射的方式对应的调用我们加了EventListener注解的方法,最终完成整个事件的发布调用流程。
private void processBean(final String beanName, final Class<?> targetType) {
    if (!this.nonAnnotatedClasses.contains(targetType) && !isSpringContainerClass(targetType)) {
        Map<Method, EventListener> annotatedMethods = null;
        try {
            // 拿到使用了@EventListener注解的方法
            annotatedMethods = MethodIntrospector.selectMethods(targetType,
                    (MethodIntrospector.MetadataLookup<EventListener>) method ->
                            AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
        }
        catch (Throwable ex) {
            // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
            if (logger.isDebugEnabled()) {
                logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
            }
        }
        if (CollectionUtils.isEmpty(annotatedMethods)) {
            this.nonAnnotatedClasses.add(targetType);
            if (logger.isTraceEnabled()) {
                logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
            }
        }
        else {
            // Non-empty set of methods
            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) {
                    // 判断是否支持该方法  这里用的DefaultEventListenerFactory spring5.0.8 写死的返回true
                    if (factory.supportsMethod(method)) {
                        // 获取类上标注了@EventListener注解的方法
                        Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                        // 将该类和方法包装为ApplicationListenerMethodAdapter对象
                        ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse);
                        if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                            // 如果是ApplicationListenerMethodAdapter对象 就把context和evaluator传进去
                            ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                        }
                        // 添加到ApplicationListener事件Set集合中去
                        context.addApplicationListener(applicationListener);
                        break;
                    }
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                        beanName + "': " + annotatedMethods);
            }
        }
    }
}

// 封装ApplicationListenerMethodAdapter对象
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
    return new ApplicationListenerMethodAdapter(beanName, type, method);
}
  • ApplicationListenerMethodAdapter类的UML图
    在这里插入图片描述
  • ApplicationListenerMethodAdapter类的属性及部分关键方法。
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {

	protected final Log logger = LogFactory.getLog(getClass());

	// 当前监听器在容器中类名,Spring容器可以通过beanName获取该类
	private final String beanName;
	// 监听器中被@EventListener注解修饰的方法
	private final Method method;

	private final Method targetMethod;

	private final AnnotatedElementKey methodKey;

	private final List<ResolvableType> declaredEventTypes;

	@Nullable
	private final String condition;

	private final int order;

	@Nullable
	private ApplicationContext applicationContext;

	@Nullable
	private EventExpressionEvaluator evaluator;
	.........省略不相关方法...........
	
	/**
	 * 该方法是实现了ApplicationListener接口的onApplicationEvent方法,当ApplicationContext容器
	 * publishEvent事件后,最后具体执行的方法,相当于观察者模式中的ConcreteObverse对象实现
	 * Obverse接口的方法。
	 */
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		processEvent(event);
	}
	
	/**
	 * Process the specified {@link ApplicationEvent}, checking if the condition
	 * match and handling non-null result, if any.
	 */
	public void processEvent(ApplicationEvent event) {
		// 解析ApplicationContext发布的事件参数信息
		Object[] args = resolveArguments(event);
		if (shouldHandle(event, args)) {
			// 通过反射的形式执行通过@EventListener注解修饰的方法
			Object result = doInvoke(args);
			if (result != null) {
				handleResult(result);
			}
			else {
				logger.trace("No result object given - no result to handle");
			}
		}
	}

	@Nullable
	protected Object doInvoke(Object... args) {
		//获取@EventListener注解修饰方法所在的Bean
		Object bean = getTargetBean();
		//将@EventListener注解修饰方法的权限设置可访问
		ReflectionUtils.makeAccessible(this.method);
		try {
			//通过反射执行该方法
			return this.method.invoke(bean, args);
		}
		catch (IllegalArgumentException ex) {
			assertTargetBean(this.method, bean, args);
			throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
		}
		catch (IllegalAccessException ex) {
			throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
		}
		catch (InvocationTargetException ex) {
			// Throw underlying exception
			Throwable targetException = ex.getTargetException();
			if (targetException instanceof RuntimeException) {
				throw (RuntimeException) targetException;
			}
			else {
				String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);
				throw new UndeclaredThrowableException(targetException, msg);
			}
		}
	}
	
	// 获取目标类
	protected Object getTargetBean() {
		Assert.notNull(this.applicationContext, "ApplicationContext must no be null");
		return this.applicationContext.getBean(this.beanName);
	}
}
  • 最后面就是触发事件监听了AbstractApplicationContext#publishEvent
public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	.........省略非必要代码........
	@Override
	public void publishEvent(ApplicationEvent event) {
		publishEvent(event, null);
	}
	/**
	 * Publish the given event to all listeners.
	 * @param event the event to publish (may be an {@link ApplicationEvent}
	 * or a payload object to be turned into a {@link PayloadApplicationEvent})
	 * @param eventType the resolved event type, if known
	 * @since 4.2
	 */
	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}else {
			// 进入multicastEvent
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}
}
  • SimpleApplicationEventMulticaster#multicastEvent->invokeListener->doInvokeListener
	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		//获取所有监听器,遍历,广播事件
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			//如果自定义实现了SimpleApplicationEventMulticaster类,并设置了线程池
			//则通过线程池异步的广播事件
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				//未实现线程池,同步的执行广播事件
				invokeListener(listener, event);
			}
		}
	}
	//invokeListener方法,调用此类的doInvokeListener方法
	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);
		}
	}
	
	@SuppressWarnings({"unchecked", "rawtypes"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			//由实现了ApplicationListener接口的类执行该方法,这里是
			//ApplicationListenerMethodAdapter类,该方法在上面已经详细讲解过了
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}
  • 到这里整个事件监听的方法都已执行完毕,本篇内容为博主的第一篇博客,限于博主知识水平有限,如有错误欢迎大家及时指正,谢谢大家。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值