深入理解:Spring监听器底层原理与使用方法
一·监听器的底层原理:
(1)底层利用观察者模式实现,项目任何位置提前注册监听器(观察者)到主题map集合里面(key为事件类型,value为对应的监听器对象集合List);项目任何位置一旦利用主题发布事件操作时,就会批量触发对应的监听器响应方法。
(2)主题发布事件方法本质就是,从主题map里面获取出对应的监听器集合,然后循环调用监听器的固定响应方法就行了,至于是同步还是异步,就看调用监听器固定方法时是否利用多线程操作了。
二·监听器机制作用:
1.解耦业务逻辑
2.实现异步处理
3.方便系统集成和扩展性
三·关于监听器的一些个人见解:
(1)监听器在程序开发中,实际上是一种开发风格或者设计模式,用不用其实都能实现需求结果。
例如:MVC三层架构开发,如果我一定要把所有代码写在控制层,这也是可以实现功能需求的,只是不太利于后面扩展延伸与二次开发罢了。
(2)利用监听器可以在各种地方获取事件源对象的所有信息
因为事件对象内部包括源对象,发布操作时又会将事件对象传给监听器,所以监听器内部能够获取所有信息,至于后续是同步操作还是异步操作,就看有没有使用多线程了。如果监听器也能够任意获取或者注册的话,那就可以实现在项目任意地方实现监控某个事件的自动化操作
四·模拟实现一个原生的监听器案例:利用监听器设计模式
第一步:创建一个事件类:MyEvent
事件类主要起一个作用:那就是通过事件对象可以获取事件源对象,监听器可以用上!
/**
* @Description 自定义事件
* @Author LiuMingFu
* @Date 2024/8/30 00:57
*/
public class MyEvent {
/**
* 事件对象构造方法
*
* @param source 源对象
* @return
* @author LiuMingFu
* @date 2024/8/30
*/
public MyEvent(Object source) {
System.out.println("进入事件对象,收到源对象:" + source);
}
}
第二步:创建一个自定义监听器,MyPersonListener类
其实本质就是一个普通类里面声明一个普通方法!监听器里面也可以根据事件对象获取事件源对象,然后进行一系列处理。
/**
* @Description 自定义监听器
* @Author LiuMingFu
* @Date 2024/8/30 00:58
*/
public class MyListener {
/**
* 事件监听响应方法
*
* @param event 事件对象
* @return
* @author LiuMingFu
* @date 2024/8/30
*/
public void onApplicationEvent(MyEvent event) {
System.out.println("进入监听器,收到事件对象:" + event);
}
}
第三步:创建自定义主题类,用于注册监听器,发布自定义事件操作
不能使用get/set方法、构造方法赋值,需要专门声明一个方法进行赋值,这就是注册监听器方法!
/**
* @Description 演示在项目任何地方发布事件
* @Author LiuMingFu
* @Date 2024/8/30 00:59
*/
public class Subject {
//监听器集合
private static Map<Object, List<MyListener>> listeners = new HashMap<>();
/**
* 注册监听器对象,且指定监视哪个事件对象
*
* @param event 事件对象
* @param listener 监听器对象
* @return
* @author LiuMingFu
* @date 2024/8/30
*/
public static void registerListener(MyEvent event, MyListener listener) {
if (listeners.get(event) != null) {
//存在则继续往集合里面添加
listeners.get(event).add(listener);
} else {
//不存在则创建集合,并添加
listeners.put(event, new ArrayList<>(Arrays.asList(listener)));
}
}
/**
* 发布自定义事件
*
* @param event 自定义事件对象
* @return
* @author LiuMingFu
* @date 2024/8/30
*/
public static void publishEvent(MyEvent event) {
System.out.println("进入主题,开始发布自定义事件");
List<MyListener> myListeners = listeners.get(event);
for (MyListener myListener : myListeners) {
myListener.onApplicationEvent(event);
}
}
}
第四步:开始测试
一旦调用depart方法,就会先去调用监听器的print方法;这样就相当于把Person类的depart方法监控起来了,也就相当于将事件源的信息告诉了另一个类监听器!!!
public class Main {
public static void main(String[] args) {
//创建一个自定义监听器
MyListener listener = new MyListener();
//创建第二个自定义监听器
MyListener listener2 = new MyListener();
//创建一个自定义事件
MyEvent myEvent = new MyEvent("自定义模拟事件对象");
//注册监听器到主题里面:这样就可以实现在项目任何地方注册监听器
Subject.registerListener(myEvent, listener);
Subject.registerListener(myEvent, listener2);
//使用主题发布自定义事件,这样可以实现在项目任何地方发布自定义事件
Subject.publishEvent(myEvent);
}
}
五·Spring框架监听器的使用步骤
1.自定义Spring框架事件:需要继承ApplicationEvent类
注意:不交给spring管理,因为Spring默认创建单例bean放入IOC容器里面,但是该事件对象是随用随创建的,并不是单例的对象
/**
* @Description 自定义Spring框架事件
* @Author LiuMingFu
* @Date 2024/8/30 00:57
*/
public class MyEvent extends ApplicationEvent {
/**
* 事件对象构造方法
*
* @param source 源对象
* @return
* @author LiuMingFu
* @date 2024/8/30
*/
public MyEvent(Object source) {
super(source);
System.out.println("进入事件对象,收到源对象:" + source);
}
}
2.自定义Spring框架监听器
方式一:需要实现ApplicationListener<T>接口
监听器注入IOC就相当于将自定义监听器注册进容器里面了,后续才能被Spring框架利用观察者模式,进行自动监听触发操作
/**
* @Description 自定义Spring框架监听器
* @Author LiuMingFu
* @Date 2024/8/30 01:12
*/
@Component //注入到spring容器中,相当于注册监听器
public class MyListener2 implements ApplicationListener<MyEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("进入监听器2,收到事件对象:" + event.getSource());
}
}
方式二:使用@EventListener注解
/**
* @Description 自定义Spring框架监听器
* @Author LiuMingFu
* @Date 2024/8/30 00:58
*/
@Component
public class MyListener {
/**
* 事件监听方法
*
* @param event 事件对象
* @return
* @author LiuMingFu
* @date 2024/8/30
*/
@EventListener(value = {MyEvent.class})
public void onApplicationEvent(MyEvent event) {
System.out.println("进入监听器,收到事件对象:" + event.getSource());
}
}
3.发布事件操作:
方式一:使用Spring框架自带的ApplicationEventPublisher
接口发布
/**
* @Description 演示在项目任何地方发布事件
* @Author LiuMingFu
* @Date 2024/8/30 00:59
*/
@RestController
public class PublisherController {
//注入Spring的事件发布器对象,框架自带
@Resource
private ApplicationEventPublisher eventPublisher;
/**
* 发布自定义事件
*
* @return
* @author LiuMingFu
* @date 2024/8/30
*/
@RequestMapping("/publish")
public void publishEvent() {
System.out.println("进入控制器,开始发布自定义事件");
//发布事件
eventPublisher.publishEvent(new MyEvent("hello lmf"));
}
}
方式二:使用IOC容器发布
@SpringBootApplication
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Main.class, args);
//利用IOC容器,发布事件
context.publishEvent(new MyEvent("ioc发布自定义事件"));
}
}
4.演示执行结果:
六·参考文献:
1.监听器入门看这篇就够了
https://segmentfault.com/a/1190000013240470
2.SpringBoot中@EventListener注解的使用
https://blog.csdn.net/weixin_48033662/article/details/126337805
3.这次终于把Spring的监听器讲明白了
https://javayz.blog.csdn.net/article/details/121623148
4.深入理解Spring的容器内事件发布监听机制
https://www.cnblogs.com/takumicx/p/9972461.html
5.spring中的监听器的使用(注解和非注解方式)
https://blog.csdn.net/erbao_2014/article/details/68924231