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 — spring中的事件驱动机制解析(四)_第1张图片
事件流程:

  • 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事件机制能很好地帮助我们消除不同业务间的耦合关系,也可以提高执行效率,应该根据业务场景灵活选择.

你可能感兴趣的:(java,spring,java,spring,设计模式,事件处理机制)