微信公众号:IT学习笔记
学习更多源码知识,欢迎关注。java
注意:spring源码分析文章对应spring版本为 5.1.xgit
目录github
1,概述spring
2.1 事件设计模式
2.2 事件监听器bash
3,结语app
要想理解spring的事件机制,我以为首先本身动手去撸一套简单的自定义事件驱动编程demo仍是很是有必要滴,由于这样有助于理解spring事件机制。固然,这里也是模仿spring的事件机制的代码,不过下面看代码实现时能够先抛开spring的事件机制相关代码,将注意力集中到这个简单demo上便可。
在看这个自定义事件驱动编程时,首先要熟悉观察者设计模式,由于事件驱动编程能够说是观察者(发布订阅)模式的具体实现。推荐个人另外一篇翻译的博文:观察者模式--设计模式(一),有须要的小伙伴们能够先学习下哈。
下面正式开始手撸代码实现,首先先放上下面代码的github地址:
由于这篇文章是spring事件机制的前置文章,所以这里自定义实现一个模拟容器(能够理解为spring容器,servltet容器等)的生命周期事件的简单demo。
先来看一下事件的总体架构图,让你们先有对事件有一个总体的认识,以下图:
1,Event接口
面向接口编程,首先先定义一个Event接口,该接口没有任何方法,能够说是事件的标志接口。
public interface Event extends Serializable {
}复制代码
2,AbstractContextEvent
AbstractContextEvent是容器事件的基本抽象类,由于事件也能够携带数据,所以这里定义了一个timestamp属性,用来记录事件的发生时间。
public class AbstractContextEvent implements Event {
private static final long serialVersionUID = -6159391039546783871L;
private final long timestamp = System.currentTimeMillis();
public final long getTimestamp() {
return this.timestamp;
}
}复制代码
3,ContextStartEvent
ContextStartEvent事件是AbstractContextEvent具体实现类,容器开始启动时触发,这里为了demo简单,这里再也不定义任何事件逻辑,只是表明容器启动时的一个标志事件类。
public class ContextStartEvent extends AbstractContextEvent {
}复制代码
4,ContextRunningEvent
ContextRunningEvent事件是AbstractContextEvent具体实现类,容器启动后时触发,这里为了demo简单,这里再也不定义任何事件逻辑,只是表明容器启动运行时时的一个标志事件类。
public class ContextRunningEvent extends AbstractContextEvent {
}复制代码
5,ContextDestroyEvent
ContextDestroyEvent事件是AbstractContextEvent具体实现类,容器销毁时触发,这里为了demo简单,这里再也不定义任何事件逻辑,只是表明容器销毁时的一个标志事件类。
public class ContextDestroyEvent extends AbstractContextEvent {
}复制代码
先来看一下事件监听器的总体架构图,让你们先有对事件监听器有一个总体的认识,以下图:
其中EventListener是全部事件监听器的基类接口,,是事件监听器的标志类接口,被全部具体的事件监听器实现。而后ContextListener接口是容器事件监听器接口,继承了EventListener,主要定义了以下事件监听方法:
void onApplicationEvent(T event);复制代码
而后ContextListener接口被三个具体的容器生命周期事件监听器实现,分别是ContextStartEventListener(监听容器启动时的ContextStartEvent),ContextRunningEventListener(监听容器启动后运行时的ContextRunningEvent)和ContextDestroyEventListener(监听容器销毁时的ContextDestroyEvent)。
下面看具体的代码实现:
public interface EventListener {
}
public interface ContextListener<T extends AbstractContextEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(T event);
}
public class ContextStartEventListener implements ContextListener<AbstractContextEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
public void onApplicationEvent(AbstractContextEvent event) {
if (event instanceof ContextStartEvent) {
System.out.println("容器启动。。。,启动时间为:" + event.getTimestamp());
}
}
}
public class ContextRunningEventListener implements ContextListener<AbstractContextEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
public void onApplicationEvent(AbstractContextEvent event) {
if (event instanceof ContextRunningEvent) {
System.out.println("容器开始运行。。。");
try {
Thread.sleep(3000);
System.out.println("容器运行结束。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ContextDestroyEventListener implements ContextListener<AbstractContextEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
public void onApplicationEvent(AbstractContextEvent event) {
if (event instanceof ContextDestroyEvent) {
System.out.println("容器销毁。。。,销毁时间为:" + event.getTimestamp());
}
}
}复制代码
先看下类图:
ApplicationEventMulticaster是发布事件的父类接口,主要定义了增长,删除,获取等操做事件监听器的的方法接口,此外,还定义了一个发布事件的方法。
SimpleApplicationEventMulticaster是ApplicationEventMulticaster事件发布器接口的默认实现类,主要承担发布事件的功能。其内部维护了一个事件监听器列表contextListeners,当发布事件时会遍历这些列表,而后再向每一个监听器发布事件,经过设置async属性来决定同步广播事件仍是异步广播事件。
下面看看实现代码:
public interface ApplicationEventMulticaster {
void addContextListener(ContextListener<?> listener);
void removeContextListener(ContextListener<?> listener);
void removeAllListeners();
void multicastEvent(AbstractContextEvent event);
}
public class SimpleApplicationEventMulticaster implements ApplicationEventMulticaster {
// 是否异步发布事件
private boolean async = false;
// 线程池
private Executor taskExecutor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
// 事件监听器列表
private List<ContextListener<?>> contextListeners = new ArrayList<ContextListener<?>>();
public void addContextListener(ContextListener<?> listener) {
contextListeners.add(listener);
}
public void removeContextListener(ContextListener<?> listener) {
contextListeners.remove(listener);
}
public void removeAllListeners() {
contextListeners.clear();
}
public void multicastEvent(AbstractContextEvent event) {
doMulticastEvent(contextListeners, event);
}
private void doMulticastEvent(List<ContextListener<?>> contextListeners, AbstractContextEvent event) {
for (ContextListener contextListener : contextListeners) {
// 异步广播事件
if (async) {
taskExecutor.execute(() -> invokeListener(contextListener, event));
// new Thread(() -> invokeListener(contextListener, event)).start();
// 同步发布事件,阻塞的方式
} else {
invokeListener(contextListener, event);
}
}
}
private void invokeListener(ContextListener contextListener, AbstractContextEvent event) {
contextListener.onApplicationEvent(event);
}
public void setAsync(boolean async) {
this.async = async;
}
}
复制代码
那么直接上测试代码,下面只演示同步发布事件的功能:
public class MockSpringEventTest {
@Test
public void testContextLifecycleEventInSync() {
// 新建SimpleApplicationEventMulticaster对象,并添加容器生命周期监听器
ApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
eventMulticaster.addContextListener(new ContextStartEventListener());
eventMulticaster.addContextListener(new ContextRunningEventListener());
eventMulticaster.addContextListener(new ContextDestroyEventListener());
// 发射容器启动事件ContextStartEvent
eventMulticaster.multicastEvent(new ContextStartEvent());
// 发射容器正在运行事件ContextRunningEvent
eventMulticaster.multicastEvent(new ContextRunningEvent());
// 发射容器正在运行事件ContextDestroyEvent
eventMulticaster.multicastEvent(new ContextDestroyEvent());
}
@Test
public void testContextLifecycleEventInAsync() throws InterruptedException {
// 新建SimpleApplicationEventMulticaster对象,并添加容器生命周期监听器
ApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
eventMulticaster.addContextListener(new ContextStartEventListener());
eventMulticaster.addContextListener(new ContextRunningEventListener());
eventMulticaster.addContextListener(new ContextDestroyEventListener());
((SimpleApplicationEventMulticaster) eventMulticaster).setAsync(true);
// 发射容器启动事件ContextStartEvent
eventMulticaster.multicastEvent(new ContextStartEvent());
// 发射容器正在运行事件ContextRunningEvent
eventMulticaster.multicastEvent(new ContextRunningEvent());
// 发射容器正在运行事件ContextDestroyEvent
eventMulticaster.multicastEvent(new ContextDestroyEvent());
// 这里没明白在没有用CountDownLatch的状况下为什么主线程退出,非后台线程的子线程也会退出???为了测试,全部先用CountDownLatch锁住main线程先
// 通过测试,原来是由于用了junit的方法,test方法线程退出后,test方法线程产生的非后台线程也随之退出,而下面的main方法启动的非后台线程则不会
// TODO 这是为何呢???难道是A子线程(非main线程)启动的B子线程会随着A子线程退出而退出?还没验证
CountDownLatch countDownLatch = new CountDownLatch(1);
countDownLatch.await();
}
public static void main(String[] args) throws InterruptedException {
// 新建SimpleApplicationEventMulticaster对象,并添加容器生命周期监听器
ApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
eventMulticaster.addContextListener(new ContextStartEventListener());
eventMulticaster.addContextListener(new ContextRunningEventListener());
eventMulticaster.addContextListener(new ContextDestroyEventListener());
((SimpleApplicationEventMulticaster) eventMulticaster).setAsync(true);
// 发射容器启动事件ContextStartEvent
eventMulticaster.multicastEvent(new ContextStartEvent());
// 发射容器正在运行事件ContextRunningEvent
eventMulticaster.multicastEvent(new ContextRunningEvent());
// 发射容器正在运行事件ContextDestroyEvent
eventMulticaster.multicastEvent(new ContextDestroyEvent());
}
}
复制代码
经过运行测试方法testContextLifecycleEventInSync(),运行结果以下截图:
好了,自定义事件驱动编程的简单demo就已经实现了。
这只是spring事件机制源码分析的前置文章,真正的源码分析请见下一篇博文: