欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring — spring中的事件驱动机制解析

程序员文章站 2022-04-15 17:56:44
1、JAVA中的事件驱动机制JDK不仅提供了Observable类、Observer接口支持观察者模式,而且也提供了EventObject、EventListener接口来支持事件监听模式。这些类都属于java.util包下。1.1 观察者模式(JDK1.0 Observable和Observer)被观察者Observable,相当于事件源和事件,执行逻辑时通知observer即可触发oberver的update,同时可传被观察者和参数:addObserver/deleteObserver/not...

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