java spring 事件驱动,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 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提供的事件驱动模型体系图:

8a618cba0d56bca18dfb98912e3f34a2.png

事件流程:

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 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 {

@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 {

@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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值