Spring 事件机制 - 源码深入解析

本篇文追踪源码详情,吐血输出,建议自己亲自动手追踪

Spring事件机制体验

要理解spring事件我们先来说说事件的几个角色概念

  • 事件(ApplicationEvent): 可以继承ApplicationEvent类表示一个事件。
  • 事件监听器(ApplicationListener): 可以在方法上使用注解 @EventListener 或者实现ApplicationListener来表示事件监听器
  • 事件发布器(ApplicationEventPublisher): 可以在业务方法注入ApplicationEventPublisher或者ApplicationContext来事件发布器

下面我们来看看一个简单的demo,当我们下完订单后,我们需要短信通知客户订单下单完成,此时我们可以使用Spring 的事件来完成这样的需求:

事件:
可以继承ApplicationEvent表示一个事件

public class OrderSuccessEvent extends ApplicationEvent implements Serializable {

	private static final long serialVersionUID = 0L;

	/**
	 * Create a new {@code ApplicationEvent}.
	 *
	 * @param source the object on which the event initially occurred or with
	 *               which the event is associated (never {@code null})
	 */
	public OrderSuccessEvent(Object source) {
		super(source);
	}
}

订单服务类(使用事件发布器发布事件)
该订单完成后需要使用事件发布器发布事件:

@Service
public class OrderService implements ApplicationContextAware {

	/**
	 * 事件发布器,他是ApplicationEventPublisher接口的实现
	 */
	private ApplicationContext applicationContext;

	public void order() {
		System.out.println("下订单成功");

		// 发布事件 通知短信
		applicationContext.publishEvent(new OrderSuccessEvent("下单成功"));

		System.out.println("事件发送后,继续做其他事情");
	}

	/**
	 * 容器启动会回调该方法,注入ApplicationContext
	 * @param applicationContext the ApplicationContext object to be used by this object
	 * @throws BeansException
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
}

事件监听器,使用@EventListener注解来表示监听某个事件
事件监听我们也可以实现接口ApplicationListener来监听事件

@Service
public class SmsService {

	@EventListener(OrderSuccessEvent.class)
	public void sendMsg(OrderSuccessEvent event) {
		String msg = (String) event.getSource();
		System.out.println("收到事件,发送通知短信:" + msg );
	}
}

测试类:

	public static void main(String[] args) {

		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);

		//测试事件
		OrderService orderService = applicationContext.getBean(OrderService.class);
		orderService.order();
	}

运行结果:

下订单成功
收到事件,发送通知短信:下单成功
事件发送后,继续做其他事情

从结果我们可以看出下单成功后,发送了一个订单成功事件,由于短信服务使用注解@EventListener监听了该事件,那么就会调用发送短信通知方法,发送短信。从该demo中我们可以体会到spring的事件机制了。

spring 事件机制需要先定义事件,然后定义事件监听器,监听器可以在方法上标注解或者实现接口来实现,最后事件发布器可以使用容器注入等方式来实现。仔细体会上面的例子就可以理解spring 事件机制了,下面我们深入探究下Spring 是怎么样实现事件机制的。

EventListenerMethodProcessor是什么

原理猜想:

在探究源码前,我们可以猜想下,我们在业务类的方法上标注了@EventListener注解,为什么当事件发布后,该方法就能感知到并执行? 如果你是熟悉Spring 生命周期机制就能猜想到,肯定是在创建对象的时候,有个后置处理器或者别的什么组件来干预进来,该组件的功能是来分析该bean有没有标注@EventListener注解,有的话肯定会把标注了**@EventListener**的方法封装成什么东西注入容器。

然后当发布某个事件的时候,肯定是取到所有该事件的监听器,然后遍历循环执行。(设计模式观察者模式)

带着这样的猜想我们来看看源码:

发现EventListenerMethodProcessor:

在容器启动的时候,我们可以打上断点查看下BeanFactory下的beanDefinitonMap的定义信息,查看下有没有关于spring事件的bena定义信息(要熟悉理解beanDefinitonMap的作用)。
Spring 事件机制 - 源码深入解析_第1张图片
根据上面的截图我们可以发现2个和spring 监听器相关的定义信息,进去看类名我们可以发现是这2个类EventListenerMethodProcessorDefaultEventListenerFactory,进行分析发现DefaultEventListenerFactory只是一个普通的bean,根据类名可以猜测出他的作用应该是用来创建监听器的。

下面我们看看EventListenerMethodProcessor继承类图:
Spring 事件机制 - 源码深入解析_第2张图片
如果熟悉spring容器的我们知道,实现了ApplicationContextAware根据回调可以获取到整个IOC容器,实现BeanFactoryPostProcessor的作用回回调postProcessBeanFactory增强IOC容器,而SmartInitializingSingleton这个作用是在bean创建完对象后会有afterSingletonsInstantiated这个回调。
Spring 事件机制 - 源码深入解析_第3张图片

下面我们只需要分析EventListenerMethodProcessorpostProcessBeanFactoryafterSingletonsInstantiated2个方法即可,

postProcessBeanFactory方法的代码很简单就是获取到所有的事件工厂保存到IOC容器中。

afterSingletonsInstantiated的调用链:
如果一个类实现了SmartInitializingSingleton接口,那么在该类创建完对象后就会回调afterSingletonsInstantiated这个方法。

该方法会从容器中取出所有的beanName,然后遍历调用processBean取出来每一个bean
Spring 事件机制 - 源码深入解析_第4张图片
该方法我标注了详细的注解,我们可以看出会去判断该bean是否有标注@EventListener注解,如果有标注就会使用监听器工厂把标注的@EventListener方法封装成事件监听器ApplicationListenerMethodAdapter,然后保存,具体过程看源码注释。默认情况下监听器工厂会使用DefaultEventListenerFactory
Spring 事件机制 - 源码深入解析_第5张图片

至此我们可以得出EventListenerMethodProcessor的作用和我们猜测的一样,就是把标注了@EventListener的方法封装成监听器ApplicationListenerMethodAdapter

监听器ApplicationListenerMethodAdapter封装信息如下:
Spring 事件机制 - 源码深入解析_第6张图片

发布事件执行过程(观察者模式典型实现)

上面分析我们得出,spring会把标注了@EventListener的方法封装成事件监听器,

那么当事件发布后的方法执行过程是怎么样的呢? 其实有了上面的分析,我们可以很简单的知道,所有的事件监听器都是ApplicationListener的实现,那么当发布时的时候,肯定会获取到所有的监听器,调用每一个监听器的onApplicationEvent方法来实现。这就是典型的观察者模式实现。事件监听器ApplicationListener接口源码如下:

Spring 事件机制 - 源码深入解析_第7张图片

下面我们来看看事件发布的调用源码:

事件的发布需要事件发布器ApplicationEventPublisher的publishEvent方法,而ApplicationContext继承了ApplicationEventPublisher,所有也可以用ApplicationContext。

下面publishEvent代码调用链很简单,就不做过多解释,请看关键注释
Spring 事件机制 - 源码深入解析_第8张图片

Spring 事件机制 - 源码深入解析_第9张图片

Spring 事件机制 - 源码深入解析_第10张图片

通过上面的源码分析,不知道你明白了spring 的事件机制了没有,看10遍不如自己动手跟踪分析一遍。其实源码很简单,体会体会就知道了。

你可能感兴趣的:(Spring源码解析,java,spring)