这是我参与更文挑战的第3天,活动详情查看: 更文挑战
书接上文的存本地的缓存那篇文章,在我们项目启动的过程中,总会有某些数据需要加载,而在数据加载完成时我们会需要进行其他的一些处理(这些处理必须在数据被加载完成才可以进行),通常情况下,我们日常是不会没事使用这玩意的,毕竟这玩意多了伤身,对于机器也一样,伤项目
可是正常开发时不用不代表项目搭建时不用,不代表后期不改动,毕竟我们的目标是星辰大海;
废话不多说,先来直呼标题
ApplicationListener是什么
这玩意是一个监听器,观察者模式的完美运用,应用程序事件侦听要实现的接口。 基于观察者设计模式的标准 java.util.EventListener 接口。 从 Spring 3.0 开始,ApplicationListener 可以一般地声明它感兴趣的事件类型。当注册到 Spring ApplicationContext 时,事件将被相应地过滤,侦听器被调用以仅匹配事件对象(机翻(手动狗头))
ApplicationListener怎么用
首先我们得理清原理
-
先来看下该接口
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E event); }
可以看出里面泛型是ApplicationEvent的,那ApplicationListener的包org.springframework.context下监听事件可以用啥
正是这四个大哥;
为了保证文章的通俗易懂,我决定对官方的注释不翻译(看不懂也没关系,后面需要英文有用)
1.**ContextRefreshedEvent :**Event raised when an ApplicationContext gets initialized or refreshed.(当ApplicationContext被初始化或刷新时引发的事件(ed完成时,所有是完成时引发时间))
2.**ContextClosedEvent:**Event raised when an ApplicationContext gets closed(ApplicationContext关闭时引发的事件).
3.**ContextStartedEvent:**Event raised when an ApplicationContext gets started(当ApplicationContext启动时引发事件).
4.**ContextStoppedEvent:**Event raised when an ApplicationContext gets stopped(当ApplicationContext停止时引发事件)。
当然存在拓展,拓展的此处不讨论
下面捡取一个也就是我项目用到的说吧ContextRefreshedEvent(没错,正是在下);其他的也是相同的思路;
首先得看定义完成bean装载触发,那必须得监听bean对吧,源码注释有个see also
org.springframework.context.event.ApplicationEventMulticaster
懒得写,写的还不清晰,直接上图
可以看到最终的实现监听类是SimpleApplicationEventMulticaster,官方给的定义是Multicasts all events to all registered listeners(所有事件注册给监听器)
先来看看抽象类AbstractApplicationEventMulticaster提供基本的监听器注册工具
这里就是获取到监听事件,那么得
首先看下加载或刷新配置的AbstractApplicationContext.refresh()方法;
注释对于我这个英文很差的都可以看懂,各位一定也行
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.准备刷新
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
告诉子类刷新bean工厂方法,如果该bean工厂存在就销毁重新创建
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
上下文准备使用bean工厂
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
上下文子类对bean处理,加载所有bean,但未实例化bean
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
调用工厂注册bean处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
注册bean
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();下面有讨论
// Initialize other special beans in specific context subclasses.
onRefresh();//暂且没做处理
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
初始化所以剩余的bean---非延迟
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
看到没这里是发布事件,下面有解释
finishRefresh();
}
}
}
**initApplicationEventMulticaster()**初始化ApplicationEventMulticaster;先去查找有没有applicationEventMulticaster这个bean,如果存在就给事件分发器,没有就交给SimpleApplicationEventMulticaster来创建;下面是源码重要的部分
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);
}
}
注意,这代码里很多地方用到了单例模式,没事可以阅读阅读!!!
**finishRefresh()**我们关注下倒数第二个方法的调用
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
publishEvent()将给定的事件发布给所有的侦听器,这里也有一段代码
// Multicast right now if possible - or lazily once the multicaster is initialized
如果可以立刻发布,或者等待发布器发布
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
这里用到了earlyApplicationEvents,这个是前面refresh方法之前的,early嘛。。。刷新前注册本地监听器;
multicastEvent(applicationEvent, eventType)会调用invokeListener(listener, event);
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
先看下getApplicationListeners(event, type)方法;该方法部分注释是:Return a Collection of ApplicationListeners matching the given event type(返回匹配的事件类型)
该方法会去调用ListenerCacheKey类
这块检索侦听结束。。。
invokeListener(listener, event)再调用doInvokeListener(listener, event);
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
看看看;回来了呦onApplicationEvent。。。
芜湖。。。看源码好累啊。。。
调用也很简单,这样(记得Component注解)
@Component
public class MytestDemo implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("调用到监听器");
}
}