Spring监听器
前言
代码耦合度不能太高,所以我们要尽量的将代码解耦,提到解耦,我们会想到使用消息队列来解耦,不过使用消息队列的话成本比较大。
我们也可以使用观察者模式来进行解耦,观察者模式就是发布订阅模式,Spring Event就是观察者模式,只是我们如果直接去写观察者模式,那么需要考虑很多东西,所以使用Spring Event便是一个不错的选择。
spring事件的原理 - 观察者模式
观察者设计模式 - 发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
Spring的事件监听有三个组成部分:
1. 事件(ApplicationEvent):监听器监听的事情。
2. 监听器(ApplicationListener): 观察者模式中的观察者, 监听器监听特定事件。
3. 事件发布器(ApplicationEventMulticaster):对外提供发布事件和增删事件监听器的接口。
目标:
- 监听器如何使用
- 监听器的类型
- 监听器的原理
- 调用事件
- 问题
1.事件多播器的作用?
2.注解方式、接口方式 两者的监听器注册在一起吗?
3.mq用的是什么设计模式?spring事件和mq的适用面?
1.监听器如何使用![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/07e82a3e956a4746b9c6336103297ee7.png#pic_center)
2.监听器的类型
2.1 内置监听器 - ApplicationContextEvent
实现 ApplicationContextEvent 的类就是内置的监听器,见名知意。
2.2 自定义监听器
类型一:基于接口 - ApplicationListener.class
类型二:基于注解 - @EventListener
3.监听器的原理
3.1 监听器的声明,调用,都是在 refresh() 方法里面进行的。
refresh()方法是spring的核心方法,其中完成了容器的初始化、Bean的生命周期也是从这里开始的。下面简单介绍一下refresh()方法中与监听器牵扯比较深的几个方法:
prepareRefresh() - 初始化上下文环境
创建事件监听器集合和事件集合
initApplicationEventMulticaster() - 创建事件多播器
事件多播器管理所有的事件监听器. 并广播事件给对应的监听器。
首先判断有没有事件多播器( applicationEventMulticaster ),如果有就直接加入容器中,如果没有就创建一个新的事件多播器并加入到容器中。
进入事件多播器看一下(ApplicationEventMulticaster.class)里面的方法都是些什么作用。
registerListeners() - 注册接口方式的监听器。如果OrderEventListenter采用的是接口方式, 那么就可以拿到. 因为它实现了ApplicationListener.拿到了, 就把监听器注册到多播器上.如果是注解方式, 不在这里注册。
在AnnotationConfigUtils.registerAnnotationConfigProcessors(xx,xx)里注册了BeanDefinition 对应的EventListenerMethodProcessor对象 , 而AnnotationConfigUtils是在AnnotationConfigServletWebServerApplicationContext构造方法里被加载。这里要提一下AnnotationConfigServletWebServerApplicationContext,他是spring boot启动入口的重要类(我这里用的是spring boot所以是这个类),可以相当于以前用xml的ClassPathXmlApplicationContext。
finishRefresh() - 发布
发布ContextRefreshedEvent()事件,表示容器都启动完成。
4.调用事件
4.1 publishEvent() 具体实现
这里具体做了3件事:
1.获取事件
2.广播事件
3.广播事件给父类的监听器
4.2 multicastEvent() 具体实现
根据线程池是否为空判断进行同步调用还是异步调用,默认同步调用。
4.3 调用事件的两种形式 - 同步、异步
默认同步调用,根据代码逻辑
当需要异步调用时需要指定 taskExecutor,代码如下:
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
// 这里指定了 taskExecutor, 就会使用异步的方式去执行
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
4.4 广播事件 - doInvokeListener(ApplicationListener listener, ApplicationEvent event)
最终调用的是监听器的onApplicationEvent方法. 这个方法就是每一个监听器都会自定义的方法,具体执行的就是我们自定义监听器的onApplicationEvent()方法中的逻辑
5.问题
1.事件多播器的作用?
事件多播器管理所有的事件监听器. 并广播事件给对应的监听器。
2.注解方式、接口方式 两者的监听器注册在一起吗?
不在一起。接口方式是在refresh()方法里面注册,注解方式是在另外一个类加载。
3.mq用的是什么设计模式?spring事件和mq的适用面?
mq用的也是观察者设计模式。分布式的微服务中,子服务与子服务之间的通信可以选择成熟的MQ中间件来做到业务的解耦;单个子服务,不同的模块中通信使用spring事件。