掘金 后端 ( ) • 2021-06-18 13:40
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body .contains-task-list{padding-left:0}.markdown-body .task-list-item{list-style:none}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

书接上文的存本地的缓存那篇文章,在我们项目启动的过程中,总会有某些数据需要加载,而在数据加载完成时我们会需要进行其他的一些处理(这些处理必须在数据被加载完成才可以进行),通常情况下,我们日常是不会没事使用这玩意的,毕竟这玩意多了伤身,对于机器也一样,伤项目

可是正常开发时不用不代表项目搭建时不用,不代表后期不改动,毕竟我们的目标是星辰大海

废话不多说,先来直呼标题

ApplicationListener是什么

这玩意是一个监听器,观察者模式的完美运用,应用程序事件侦听要实现的接口。 基于观察者设计模式的标准 java.util.EventListener 接口。 从 Spring 3.0 开始,ApplicationListener 可以一般地声明它感兴趣的事件类型。当注册到 Spring ApplicationContext 时,事件将被相应地过滤,侦听器被调用以仅匹配事件对象(机翻(手动狗头))

ApplicationListener怎么用

首先我们得理清原理

  1. 先来看下该接口

    public interface ApplicationListener 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 {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("调用到监听器");
    }
}
复制代码
相关内容