一. 观察者模式
观察者模式又称发布-订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态变化时,会通知所有的观察者对象,让他们自动更新自己;
观察者模式结构图如下:
观察者模式中如下角色:
- Subject:被观察者(抽象主体),被观察者把所有观察者对象保存在一个集合里,每个主体都可以有任意数量的观察者,抽象主体提供一个接口,可以增加和删除观察者对象;
- Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主体更新通知时更新自己;
二. Spring ApplicationListener的应用
通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现 ApplicationContext 的事件处理,如果容器中有一个 ApplicationListener bean,当 ApplicationContext 发布 ApplicationEvent 时,ApplicationListener bean 将自动被触发;
1. ApplicationEventPublisher
封装事件发布功能的接口,它有两个接口;
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
我们的 ApplicationContext 会实现这个接口,看如下类继承图;
2. ApplicationEvent
ApplicationEvent 是 Spring 应用程序中的事件,在 Spring 容器中发布的事件应该都继承 ApplicationEvent;
//------------------------ ApplicationEvent --------------------------
public abstract class ApplicationEvent extends EventObject {
/** System time when the event happened. */
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
}
// ------------------------- EventObject ----------------------------
public class EventObject implements java.io.Serializable {
/**
* 事件最初触发的对象
*/
protected transient Object source;
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
}
3. ApplicationListener
ApplicationListener 是监听器,它有一个抽象方法 onApplicationEvent();
public interface ApplicationListener<E extends ApplicationEvent>
extends EventListener {
void onApplicationEvent(E event);
}
我们往容器中注册的监听器都应该实现 ApplicationListener,并实现它的抽象方法 onApplicationEvent(),需要注意实现泛型接口的方式;示例如下:
@Component
public class TestApplicationListener01 implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println(contextRefreshedEvent);
System.out.println("TestApplicationListener01............................");
}
}
由上面的流程,只需要在容器中注册实现了 ApplicationListener 的 bean,当 ApplicationContext 发布事件的时候,就会被监听器自动监听;
4. Spring的内置事件
Spring 有一些内置的事件,当完成某种操作时会发出某些事件动作。比如监听 ContextRefreshedEvent 事件,当所有的 bean 都初始化完成并被成功装载后会触发该事件,实现 ApplicationListener< ContextRefreshedEvent > 接口可以收到监听动作,然后可以写自己的逻辑。
- ContextRefreshedEvent:ApplicationContext 容器初始化或刷新触发该事件。此处说的初始化,是指所有的 bean 被成功加载,后处理的 bean 被检测激活,所有的 singleton bean 被预初始化,ApplicationContext 容器已就绪可用。
- ContextStartdEvent:当使用 ApplicationContext 的子接口 ConfigurableApplicationContext 接口的start() 启动 ApplicationContext 容器时触发该事件。容器管理生命周期的 bean 实例将获得一个指定的启动信号,这在经常需要停止后重新启动的场合比较常见。
- ContextClossedEvent:当使用 ConfigurableApplicationContext 接口的 close() 关闭ApplicationContext容器时触发该事件。
- ContextStoppedEvent:当使用 ConfigurableApplicationContext 接口的 stop() 使ApplicationContext 容器停止时触发该事件 。此处的停止意味着,容器管理生命周期的 bean 实例将获得一个指定的停止信号。被停止的 Spring 容器可以再次通过调用 start() 重新启动。
- RequestHandledEvent:Web 相关的事件,只能应用于使用 DispatcherServlet 的 Web 应用中。在使用 Spring 作为前端的 MVC 控制器时,当 Spring 处理用户请求结束后,系统会自动触发该事件。
比如要监听 ContextRefreshedEvent 时可以实现 ApplicationListener 接口;
@Component
public class TestApplicationListener01 implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println(contextRefreshedEvent);
System.out.println("TestApplicationListener01............................");
}
}
5. 自定义事件
我们自定义事件和自定义监听器,如下:
EmailEvent:
@Getter
@Setter
public class EmailEvent extends ApplicationEvent {
private String address;
private String text;
public EmailEvent(Object source) {
super(source);
}
public EmailEvent(Object source, String address, String text) {
super(source);
this.address = address;
this.text = text;
}
}
TestEmailListener:
@Component
public class TestEmailListener implements ApplicationListener<EmailEvent> {
@Override
public void onApplicationEvent(EmailEvent event) {
System.out.println(event);
System.out.println("邮件内容:" + event.getText());
System.out.println("邮件地址:" + event.getAddress());
}
}
测试事件和监听器;
//------------------------------ ListenerController ----------------------------
@Controller
@ResponseBody
@RequestMapping("/listener")
public class ListenerController {
@Autowired
private ListenerService listenerService;
@RequestMapping("/01")
public String testEmailListener() {
listenerService.testListener();
return "ok";
}
}
// ------------------------------ ListenerService ----------------------------
@Service
public class ListenerService implements ApplicationContextAware {
private ApplicationContext context;
public void testListener() {
EmailEvent emailEvent = new EmailEvent(this, "jx", "zengqiang");
context.publishEvent(emailEvent);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
}
调用 /listener/01 接口,运行结果如下:
com.example.myspringpro.listener.EmailEvent[source=com.example.myspringpro.service.ListenerService@7e2e5794]
邮件内容:zengqiang
邮件地址:jx
三. ApplicationListener原理
我们以 ContextRefreshEvent 事件来看 ApplicationListener 的原理;
1. AbsApplicationContext#refresh()
AbstractApplicationContext 的 refresh() 刷新容器;
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh =
this.applicationStartup.start("spring.context.refresh");
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess =
this.applicationStartup.start("spring.context.beans.post-process");
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
initMessageSource();
// 1.初始化ApplicationEventMulticaster
initApplicationEventMulticaster();
onRefresh();
// 2.往容器中注入所有的 ApplicationListener
registerListeners();
finishBeanFactoryInitialization(beanFactory);
// 3.容器刷新完成,发布ContextRefreshEvent事件
finishRefresh();
} catch (BeansException ex) {
} finally {
resetCommonCaches();
contextRefresh.end();
}
}
}
1.1 initApplicationEventMulticaster()
- 先去容器中找有没有 id = “applicationEventMulticaster” 的组件;
- 如果没有的话,this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory),并将该 applicationEventMulticaster 注入到容器中;
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
ApplicationEventMulticaster.class);
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
this.applicationEventMulticaster);
}
}
1.2 registerListeners()
往容器中注入所有的 ApplicationListener,往 ApplicationEventMulticaster 中添加所有的监听器;
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 往 ApplicationEventMulticaster 中添加所有的监听器
// 后处理器会初始化这些监听器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().
addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
1.3 finishRefresh()
容器刷新完成,并发布 ContextRefreshedEvent 事件;
核心方法 publishEvent(),我们可以重点看一下该接口;
protected void finishRefresh() {
this.initLifecycleProcessor();
this.getLifecycleProcessor().onRefresh();
// 发布ContextRefreshedEvent事件
this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
LiveBeansView.registerApplicationContext(this);
}
2. AbsApplicationContext#publishEvent()
AbstractApplicationContext 的 publishEvent() 如下;
public void publishEvent(ApplicationEvent event) {
// 事件类型为null
publishEvent(event, null);
}
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// 将事件装饰为ApplicationEvent
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)
applicationEvent).getResolvableType();
}
}
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
// 核心方法
// getApplicationEventMulticaster()获取事件的多播器
// 一般为 SimpleApplicationEventMulticaster,调用它的 multicastEvent()
getApplicationEventMulticaster().multicastEvent(applicationEvent);
}
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent)
.publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
3. SimpleApplicationEventMulticaster
默认的事件多播器:SimpleApplicationEventMulticaster;
AbstractApplicationContext 的 publishEvent() 会调用到 multicastEvent();
3.1 multicastEvent()
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType :
resolveDefaultEventType(event));
// 如果有 Executor 的话,可以使用线程池的 execute() 执行 onApplicationEvent()
// 默认情况下 executor == null,会通过当前线程执行 onApplicationEvent()
Executor executor = getTaskExecutor();
// getApplicationListeners(event, type) 获取当前 event 的 ApplicationListener
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
// 调用执行listener
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener,
ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
// 调用执行listener
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener,
ApplicationEvent event) {
try {
// 执行ApplicationListener的onApplicationEvent()
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
throw ex;
}
}