spring — spring中的事件驱动机制解析
1、JAVA中的事件驱动机制
JDK不仅提供了Observable类、Observer接口支持观察者模式,而且也提供了EventObject、EventListener接口来支持事件监听模式。这些类都属于java.util包下。
1.1 观察者模式(JDK1.0 Observable和Observer)
-
被观察者Observable,相当于事件源和事件,执行逻辑时通知observer即可触发oberver的update,同时可传被观察者和参数:addObserver/deleteObserver/notifyObservers()等,具体请参考javadoc。
-
观察者Observer,提供了观察者需要的主要抽象:update(Observable o, Object arg),此处还提供了一种推模型(目标主动把数据通过arg推到观察者)/拉模型(目标需要根据自己去拉数据,arg为null)。
源码分析:
// 观察者,实现此接口即可
public interface Observer {
// 当被观察的对象发生变化时候,这个方法会被调用
//Observable o:被观察的对象
// Object arg:传入的参数
void update(Observable o, Object arg);
}
// 它是一个Class
public class Observable {
// 是否变化,决定了后面是否调用update方法
private boolean changed = false;
// 用来存放所有`观察自己的对象`的引用,以便逐个调用update方法
// 需要注意的是:1.8的jdk源码为Vector(线程安全的),有版本的源码是ArrayList的集合实现;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o); //添加一个观察者 注意调用的是addElement方法,添加到末尾 所以执行时是倒序执行的
public synchronized void deleteObserver(Observer o);
public synchronized void deleteObservers(); //删除所有的观察者
// 循环调用所有的观察者的update方法
public void notifyObservers();
public void notifyObservers(Object arg);
public synchronized int countObservers() {
return obs.size();
}
// 修改changed的值
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
}
1.2 发布订阅模式(JDK1.1 EventListener和EventObject)
事件机制一般包括三个部分:EventObject,EventListener和Source。
- EventObject:事件状态对象的基类,它封装了事件源对象以及和事件相关的信息。所有java的事件类都需要继承该类
- EventListener:是一个标记接口,就是说该接口内是没有任何方法的。所有事件监听器都需要实现该接口。事件监听器注册在事件源上,当事件源的属性或状态改变的时候,调用相应监听器内的回调方法(自己写)
- Source:事件源,即触发事件的对象,他里面必须含有监听它的监听器们;
缺点:对比上面的观察者模式,监听模式使用起来确实非常的繁琐,且还线程安全问题还得自己考虑解决。
2、Spring中的事件机制
首先看一下Spring提供的事件驱动模型体系图:
事件流程:
- Spring提供了ApplicationEventPublisher接口作为事件发布者,ApplicationContext接口继承了该接口,担当着事件发布者的角色。
- Spring提供了ApplicationEventMulticaster接口,负责管理ApplicationListener 和 真正发布ApplicationEvent(ApplicationContext是委托给它完成的)
- ApplicationListener实现了JDK的EventListener,但它抽象出一个onApplicationEvent方法,使用更方便。
- ApplicationEvent继承自EventObject。 它就是媒介,充当介质的作用。
- ApplicationEventPublisher最终都是委托给ApplicationEventMulticaster去完成的。当然你也可以自己去实现一个ApplicationEventMulticaster
在spring中,容器管理所有的 bean。是ApplicationEvent 驱动的,一个ApplicationEvent publish了,观察这个事件的监听者就会收到通知。
在IOC容器源码中,与EventListener有关联的步骤
- initApplicationEventMulticaster():初始化事件多播器
- registerListeners():注册Listener到多播器
- finishBeanFactoryInitialization(beanFactory):涉及将@EventListener转为普通Listener
- finishRefresh():发布容器刷新完成事件ContextRefreshedEvent
ApplicationListener类解析:
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 此子接口提供了泛型,和提供了统一的处理方法
void onApplicationEvent(E event);
}
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 这个接口是Spring4.2后提供的,可以发布任意的事件对象(即使不是ApplicationEvent的子类了)
// 当这个对象不是一个ApplicationEvent,我们会使用PayloadApplicationEvent来包装一下再发送
// 比如后面会建讲到的@EventListener注解标注的放 就是使用的它
void publishEvent(Object event);
}
通过Spring源码我们了解到,Spring容器刷新的时候会发布ContextRefreshedEvent事件,因此若我们需要监听此事件,直接写个监听类即可:
@Slf4j
@Component
public class ApplicationRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Object source = event.getSource();
// 此处的source就是ApplicationContext这个对象
System.out.println(source);
//容器此时已经准备好了,可以做你该做的事了~......(请注意:若存在父子容器或者多个容器情况,此方法会被执行多次,请务必注意是否幂等)
}
}
发布事件监听demo:
public class MyAppEvent extends ApplicationEvent {
public MyAppEvent(Object source) {
super(source);
}
}
// 写个监听器,然后交给容器管理即可
@Slf4j
@Component
public class MyEventListener implements ApplicationListener<MyAppEvent> {
@Override
public void onApplicationEvent(MyAppEvent event) {
Object source = event.getSource();
long timestamp = event.getTimestamp();
System.out.println(source);
System.out.println(timestamp);
//doSomething
}
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
// 发布自己的事件
applicationContext.publishEvent(new MyAppEvent("this is test event"));
}
// 输出:
this is test event
1553581974928
总结:
使用spring事件机制能很好地帮助我们消除不同业务间的耦合关系,也可以提高执行效率,应该根据业务场景灵活选择.
本文地址:https://blog.csdn.net/qq_38658567/article/details/109817908
推荐阅读
-
spring中FactoryBean中的getObject()方法实例解析
-
Spring中Bean的生命周期使用解析
-
基于Spring Cloud Netflix的TCC柔性事务和EDA事件驱动示例
-
spring中FactoryBean中的getObject()方法实例解析
-
spring-boot-2.0.3不一样系列之番外篇 - springboot事件机制,绝对有值得你看的地方
-
spring — spring中的事件驱动机制解析
-
一次业务代码重构的总结:spring中事件驱动机制
-
一次业务代码重构的总结:spring中事件驱动机制
-
解析Spring中@Bean的实现原理
-
Spring中Bean的生命周期使用解析