目标:

1. 监听器如何使用

2. 监听器的原理

3. 监听器的类型

4. 多播器的概念和作用

5. 接口类型的监听器是如何注册的?

6. 注解类型的监听器和如何注册的?

7. 如果想在所有的bean都加载完成以后做一些事情, 怎么办?


一. 监听器的使用

为什么要学习监听器呢?学习监听器主要学习监听器的设计思想。 比如,我们之前研究过的nacos,他就是使用监听器进行集成的。所以了解监听器的原理,就很重要了。

首先, 我们要知道监听器如何使用。

1.1 Spring事件的原理

原理: 是观察者模式

Spring的事件监听有三个组成部分:

1. 事件(ApplicationEvent):要广播,发送的消息. 监听器监听的事情
2. 监听器(ApplicationListener): 观察者模式中的观察者, 监听器监听特定事件, 并在内部定义了事件发生后的相应逻辑.
3. 事件发布器(ApplicationEventMulticaster):对应于观察者模式中的被观察者/主题.负责通知观察者. 对外提供发布事件和增删事件监听器的接口.维护事件和事件监听器之间的关系.并在事件发生时负责通知事件监听器.

1.2 认识监听器

上面认识了监听器. 接下来看一个例子. 通过例子来理解.

就好比现在有一个消息, 比如说: 下单后减库存. 减库存就是一个事件, 这个事件需要一个事件播放器, 将事件播放出去. 然后另一端事件监听器, 接收到信息,进行处理.

比如:下面的demo

有一个订单Order :

package com.lxl.www.events;

/**
* Description
*
* DATE 2020/11/17.
*
* @author lxl.
*/
public class Order {
private Integer id; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
}
}

接下来, 有一个订单事件. 订单的操作,带来的库存的增减. 就是一个订单事件

package com.lxl.www.events;

import org.springframework.context.ApplicationEvent;

import java.io.Serializable;

/**
* Description
* 订单的事件
*
* 事件的分类: 分为自定义事件和内置事件
* DATE 2020/11/17.
*
* @author lxl.
*/
public class OrderEvent extends ApplicationEvent implements Serializable { private static final long serialVersionUID = 1L; private String name;
public OrderEvent(Object event, String name) {
super(event);
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

第三: 事件监听器 ,事件监听器用来监听事件. 当OrderEvent发布减库存消息的时候, 事件监听器就能听到.

package com.lxl.www.events;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; /**
* Description
* OrderEvent的事件监听器
*
*
* DATE 2020/11/17.
*
* @author lxl.
*/
@Component
public class OrderEventListenter implements ApplicationListener<OrderEvent> {
/**
* 当某一个事件发布的时候, 就会触发事件监听器
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(OrderEvent event) {
if (event.getName().equals("减库存")) {
System.out.println("事件监听器 监听到 减库存");
}
}
}

是不是和mq相差不多.

mq也是一个订阅者,一个发布者.

下面写一个main方法, 运行看看监听器的效果

package com.lxl.www.events;

import org.springframework.beans.factory.parsing.SourceExtractor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; /**
* 监听器的使用
*/
public class MainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class); /**
* 使用场景: 比如有一个订单, 由用户下单了,那么对应的就要减库存.其实下单和减库存不需要是串行.
* 通常, 我们会使用一个mq去处理减库存的情况. 也就是采用异步的方式.
*
* 那么, 监听器的远离和mq是类似的. 我们可以手动设置采用同步还是异步的方式处理.
*/
Order order = new Order();
order.setId(1);
System.out.println("下单"); // 发布事件. 当在这里发布事件, 那么就会被事件监听器监听到
ctx.publishEvent(new OrderEvent(order, "减库存"));
System.out.println("日志.....");
}
}

输出结果

下单
事件监听器 监听到 减库存
日志.....

监听器使用的设计模式是: 观察者模式.

1.3 监听器的类型

监听器有两种类型: 一种是内置的监听器, 一种是自定义监听器.

1.3.1 内置监听器

spring设置了一个内置监听器的父类.

public abstract class ApplicationContextEvent extends ApplicationEvent {

    /**
* Create a new ContextStartedEvent.
* @param source the {@code ApplicationContext} that the event is raised for
* (must not be {@code null})
*/
public ApplicationContextEvent(ApplicationContext source) {
super(source);
} /**
* Get the {@code ApplicationContext} that the event was raised for.
*/
public final ApplicationContext getApplicationContext() {
return (ApplicationContext) getSource();
} }

实现了ApplicationContextEvent的类就是内置的监听器. 我们使用快捷键ctrl + H, 查看都有哪些类实现了 ApplicationContextEvent

一共有5各类实现了ApplicationContextEvent.

Event  说明
ContextRefreshEvent

当容器被实例化或者refresh时发布.如调用refresh()方法. 此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化,所有的容器对象

都已经准备好可使用. 如果容器支持热重载,则refresh()可以被触发多次(XmlWebApplicationContext支持热刷新, 而GenericApplicationContext不支持热刷新)

ContextStartedEvent 当容器启动时发布, 即调用start()方法, 已启用意味着所有的lifecycle都已显示收到了start的信号
ContextStoppedEvent 当容器停止时发布. 即调用stop()方法, 既所有的lifecycle bean都已显示接收了stop信号, 关闭的容器可以通过start()方法重启
ContextClosedEvent 当容器关闭时发布. 即调用close()方法, 关闭意味着所有的单例bean都已被销毁. 关闭的容器不能被重启或refresh()

1. ContextRefreshEvent: 当容器被实例化或者refresh时发布

我们来看看一下源码.

从refresh()源码进入.

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 进入构造函数, 首先调用自身的构造方法this();
// 调用自身的构造方法之前, 要先调用父类的构造方法
this();
// register配置注册类
register(componentClasses);
// ioc容器刷新接口--非常重要
refresh();
}
/**
* refresh是spring最核心的方法, 里面包含了整个spring ioc的全过程, 包括spring加载bean到销毁bean的全过程
* 学习spring, 就是学习里面的13个方法, 如果13个方法都学完了, 基本上就打通了
* @throws BeansException
* @throws IllegalStateException
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新上下文环境
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
//2. 获取告诉子类初始化bean工厂, 不同工厂不同实现
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();         ......
// Last step: publish corresponding event.
//最后容器刷新 发布刷新时间(spring cloud是从这里启动的 )
finishRefresh();
}
      
      ......     }
}

进入到finishRefresh()方法

protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 清除上下文缓存
clearResourceCaches(); // Initialize lifecycle processor for this context.
// 注册lifecycleProcessor声明周期处理器
// 作用: 当ApplicationContext启动或停止时, 他会通过LifecycleProcessor来与所有声明的bean进行交互
initLifecycleProcessor(); // Propagate refresh to lifecycle processor first.
// 为实现了SmartLifeCycle并且isAutoStartup, 自动启动的Lifecycle调用start()方法
getLifecycleProcessor().onRefresh();
    // 发布容器启动完毕事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

我们看到有一个发布事件. 这个事件的作用是通知容器已经启动完毕. 注意看, 里面发布的是什么事件? new ContextRefreshedEvent(this). 发布的是ContextRefreshedEvent事件.

下面有一个问题:  怎么样可以在所有的bean创建完以后做扩展代码呢?

上面我们说到了, 当所有的bean都创建完以后, 会调用publishEvent(new ContextRefreshedEvent(this));发布容器启动完毕的事件.

这时我们可以自定义一个监听器, 用来监听ContextRefreshedEvent事件.

/**
* 自定义一个事件监听器, 用来监听ContextRefreshedEvent事件
*/
@Component
public class ContextRefreshedEventListener { /**
* 声明这是一个事件监听器, 监听的是ContextRefreshedEvent事件.
* @param event
*/
@EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
  ....
    // 在所有的bean创建完以后, 写一些逻辑代码 }
}

然后, 在里面写上我们需要在容器都创建完毕之后执行的逻辑代码.

2. ContextClosedEvent: 当容器关闭时发布

还是先来看源码, spring是在何时发布的这个事件.

protected void doClose() {
// Check whether an actual close attempt is necessary...
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
} LiveBeansView.unregisterApplicationContext(this); try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this
));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
} // Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
} // Destroy all cached singletons in the context's BeanFactory.
destroyBeans(); // Close the state of this context itself.
closeBeanFactory(); // Let subclasses do some final clean-up if they wish...
onClose(); // Reset local application listeners to pre-refresh state.
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
} // Switch to inactive.
this.active.set(false);
}
}

在doClose()的时候, 发布了publishEvent(new ContextClosedEvent(this));事件

我们看一看具体发布的是什么事件呢? 就是ContextClosedEvent事件

假如: 我们想要在容器关闭的时候做一些扩展, 就可以写一个监听器, 在容器关闭的时候监听ContextClosedEvent事件

Spring内置的事件, 我们就不用再自己定义了. 我们需要做的就是定义一个监听器, 监听事件就可以了.

1.3.2 自定义监听器

不是spring定义的监听器, 也就是我们自己定义的监听器就是自定义监听器. 下面来看看自定义监听器的两种类型.

类型一: 基于接口

@Component
public class HelloEventListener implements ApplicationListener<OrderEvent> { @Override
public void onApplicationEvent(OrderEvent event) {
if (event.getName().equals("减库存")) {
System.out.println("减库存....");
}
}
}

事件监听器需要实现ApplicationListener接口, 这是一个泛型接口, 泛型的类型就是事件的类型.

其次, 这个监听器需要是spring容器托管的bean, 因此加上了@Component注解, 里面只有一个方法onApplicationEvent, 就是事件触发时执行的内容.

类型二: 基于注解

@Component
public class OrderEventListener { @EventListener(OrderEvent.class)
public void onApplicationEvent(OrderEvent event) {
if (event.getName().equals("减库存")) {
System.out.println("减库存....");
}
} }

在方法上面添加注解@EventListener(OrderEvent.class) 监听的是哪个事件呢?OrderEvent.class

我们在定义监听器的时候, 可以选择是基于接口的方式还是基于注解的方式.

二. 监听器源码

首先, 监听器的声明,调用,都是在refresh()方法里面进行,我们先来看看refresh()的整体脉络. 其中标红的部分是和监听器有关系的模块.

这里面的第五步, 第九步, 第十一步, 都详细的分析过. 下面主要看看和监听器有关的几步.

2.1 准备上下文环境prepareRefresh()

在准备上下文环境的时候, 我们看看做了哪些事情

1. 设置了容器当期的状态, 是激活状态

2. 初始化了属性源initPropertySources();.

在AbstractApplicationContext类中没有实现这个方法. 这是一个父类定义的方法. 比如:我们可以自定义一个类, 然后重写initPropertySource, 在改方法中设置一个环境变量abc, 那么在容器启动的时候, 就会去环境变量中检查, 是否环境变量中有这个属性, 如果没有就会抛出异常.

3. 接下来就是验证上面环境变量中指定的属性是否存在了. getEnvironment().validateRequiredProperties(); 不存在就抛出异常MissingRequiredPropertiesException

4. 然后接下来,和事件有关的一步, 创建了早期的事件监听器

     // 创建早期的事件监听器.
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

这里有一个问题, 什么是早期的事件监听器呢? 早对应的就是晚了. 早期指的是多早呢?

早期事件指的是事件监听器还没有注册到事件多播器的时候.

早期定义的事件不需要手动的publishEvent, 在RegisterListener()阶段会自动发布早期事件.

什么是早期的事件监听器呢? 早对应的就是晚了. 早期指的是多早呢?

早期事件指的是事件监听器还没有注册到事件多播器的时候.

早期定义的事件不需要手动的publishEvent, 在RegisterListener()阶段会自动发布早期事件.

在这里就定义了一个集合, 这个集合就是后面事件监听器集合. 在这里只是进行的初始化

5. 初始化保存早期事件的集合

this.earlyApplicationEvents = new LinkedHashSet<>();

在第一步: 对事件的操作就是初始化. 一共初始化了两个集合, 一个是早期事件监听器集合, 一个是早期的事件集合

2.2 初始化bean工厂

我们现在经常使用的beanFactory有两种,一种是xml方式的, 另一种是注解方式的. 其实使用注解的更多一些. xml和注解方式的bean工厂在初始化的时候也是有区别的.

从上图可以看出, 获取两种方式的bean工厂的区别

1. AbstractRefreshableApplicationContext: 基于xml配置文件的方式
2. GenericApplicationContext: 基于注解的方式.

基于注解实现的里面代码很简单, 只是刷新的beanFactory. 没有耦合加载beanDefinition的流程.
基于xml实现的代码, 里面耦合了加载beanDefinition

先来看看基于注解方式的, 基于注解方式只是指定了bean工厂的序列化ID

@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
// 指定bean工厂的序列化ID
this
.beanFactory.setSerializationId(getId());
}

再来看看基于xml方式的, 基于xml方式的 除了指定了bean工厂的序列化id, 还耦合加载了beanDefinition

@Override
protected final void refreshBeanFactory() throws BeansException {
// 判断bean工厂是否初始化过, 如果已经初始化过那么销毁并关闭
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();

}
try {
// 重新创建一个bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置序列化id
beanFactory.setSerializationId(getId());
// 设置个性化属性
customizeBeanFactory(beanFactory);
// 加载BeanDefinition
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

看上面的步骤.

1. 先看看是否已经有过工厂了, 如果已经有了,那么销毁,关闭

2. 重新创建了一个空的新的工厂

3. 设置新工厂的序列化id

4. 设置个性化属性bean

5. 加载bean定义. 我们看到, 使用xml方式会加载bean定义

6. 返回bean工厂对象

这一步: 主要是初始化了bean工厂

2.3 对bean工厂进行填充属性prepareBeanFactory(beanFactory);

这一步是和监听器有关系的. 我们先来看看源码

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
// 设置bean工厂的类加载器为当前的application应用的加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 为bean工厂设置标准的SPEL表达式解析器对象(StandardBeanExpressionResolver)
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 为bean工厂设置一个PropertiesEditor属性资源编辑器(用于后面给bean对象赋值)
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks.
/**
* 注册一个完整的ApplicationContextAwareProcessor后置处理器, 用来处理ApplicationContextAware
* ApplicationContextAwareProcessor是一个bean的后置处理器. 怎么使用呢?
*
* 在bean初始化完成以后, 会调用一堆的bean后置处理器.
* 在初始化的地方,其实只调用了三个bean后置处理器. 那么其他的后置处理器是什么时候调用的呢?
* 就是在这里, 这里注册了 ApplicationContextAwareProcessor.
* 在ApplicationContextAwareProcessor#invokeAwareInterfaces方法里调用了其他的aware
* 那么invokeAwareInterfaces方法是在哪里调用呢?
* 是在ApplicationContextAwareProcessor#postProcessBeforeInitialization调用的
* postProcessBeforeInitialization是在bean初始化之前会调用的后置处理器
*
* 然后在通过addBeanPostProcessor()方法, 将bean的后置处理器添加到beanPostProcessors集合中
*/
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
/**
* 忽略部分接口的函数方法, 在populateBean(创建bean的第二步:属性赋值)时
* 因为下面接口都有set***方法, 这些方法不特殊处理将会自动注入到容器中.
*
* 忽略了这么多的Aware, 这是怎么回事呢? 因为Aware里面的方法都是以set开头的. 当在创建bean, 设置属性的时候,
* 会给带有set+属性名的方法赋值. 而Aware的这些方法要忽略掉, 为什么忽略掉呢?
*
* 比如:EnvironmentAware 里面设置了一些环境变量, 这些环境变量是不需要进行属性装配的, 所以要把他们排除掉
*/
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
/**
* 将beanFactory类型的实例注册解析
*
* 当注册了依赖解析以后, 例如当注册了对BeanFactory.class的解析依赖后,
* 当bean属性注入的时候, 一旦检测到属性为beanFactory类型. 便会将BeanFactory的实例注册解析
* 为什么呢?
* 比如:
* @Autowired
* ApplicationContext applicationContext 为什么能够自动装配, 通过@Autowired引入呢? 就是在这里装配的.
* 这个也是在注入属性popularBean的时候体现的
*
*/
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners.
// 注册事件监听器探测器后置处理器接口, ApplicationListenerDetector 解析接口方式的监听器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
} // Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}

1. 设置bean工厂的类加载器为: 当前的application应用的加载器

2. 为bean工厂设置标准的SPEL表达式解析器对象, 这个解析器对象是谁呢? 就是StandardBeanExpressionResolver

3. 为bean工厂设置一个PropertiesEditor属性资源编辑器, 用于后面给bean对象赋值

4. 给bean工厂注册了一个ApplicationContextAwareProcessor后置处理器. 这里说说这个后置处理器类. 这个类有什么作用呢?

在bean初始化完成以后, 会调用一堆的bean后置处理器

在doCreateBean()中找到第三步: 初始化bean

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 在初始化完成以后, 调用aware
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 在初始化的时候, 会调用很多的aware.
invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 在初始化之前调用bean的后置处理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
// 调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 再初始化之后调用bean的后置处理器
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
} return wrappedBean;
}

我们看到, 在初始化bean的时候, 调了很多Aware, invokeAwareMethods(beanName, bean);

/**
* 这里主要有三类aware
* @param beanName
* @param bean
*/
private void invokeAwareMethods(final String beanName, final Object bean) {
/**
* 在这里调用的aware只有三类, 我们去BeanFactory中看, 他有一大堆的aware要调用,
* 那么其他的aware是在哪里调用的呢?
*/
if (bean instanceof Aware) {
// 实现了BeanNameAware的bean
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
// 实现了BeanClassLoaderAware接口
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
// 实现了BeanFactoryAware
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}

如上代码, 我们看到, 其实知道用了3中类型的Aware. 分别是BeanNameAware, BeanClassLoaderAware 和 BeanFactoryAware.

那么其他的Aware呢? 我们看beanFactory接口的注释可以看到, 会调用很多Aware

在初始化的地方,其实只调用了三个bean后置处理器. 那么其他的后置处理器是什么时候调用的呢?

就是在这里, 这里注册了 ApplicationContextAwareProcessor.

在ApplicationContextAwareProcessor#invokeAwareInterfaces方法里调用了其他的aware

/**
* 判断bean是否实现了各种Aware
* @param bean
*/
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}

而这个方法, 什么时候执行呢? 在初始化之前调用Bean的后置处理器执行的ApplicationContextAwareProcessor#postProcessBeforeInitialization

@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
} AccessControlContext acc = null; if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
} if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
} return bean;
}

然后在通过addBeanPostProcessor()方法, 将bean的后置处理器添加到beanPostProcessors集合中.

5. 忽略部分接口的函数方法. 这些接口主要是Aware.

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

忽略了这么多的Aware, 这是怎么回事呢?为什么忽略掉呢? 因为Aware里面的方法都是以set开头的. 当在创建bean, 设置属性的时候,

会给带有set+属性名的方法赋值.在populateBean(创建bean的第二步:属性赋值)时 因为下面接口都有set***方法, 这些方法不特殊处理将会自动注入到容器中.

比如:EnvironmentAware 里面设置了一些环境变量, 这些环境变量是不需要进行属性装配的, 所以要把他们排除掉

6. 将beanFactory类型的实例注册解析

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
当注册了依赖解析以后, 例如当注册了对BeanFactory.class的解析依赖后,
当bean属性注入的时候, 一旦检测到属性为beanFactory类型. 便会将BeanFactory的实例注册解析
为什么呢?
比如:
@Autowired
ApplicationContext applicationContext; .
为什么能够自动装配, 通过@Autowired引入呢? 就是在这里装配的
这个也是在注入属性popularBean的时候体现的

7. 注册了一个解析接口方式的监听器的 BeanPostProcessor.

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

我们来看看ApplicationListenerDetector 类, 其下的 postProcessAfterInitialization方法, 是在createBean的第三步初始化之后执行的bean的后置处理器.

 @Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
/*
* 注册接口类型的监听器. 将其添加到applicationContext中
* 之所以要在这里在加一次, 是为了处理懒加载情况
*/
this.applicationContext.addApplicationListener((ApplicationListener<?>
) bean);
}
else if (Boolean.FALSE.equals(flag)) {
// 这里是处理早期事件.
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}

我们看这个方法, 方法一进来就判断,是否是实现了ApplicationListener接口. 也就是说, 上面我们输了注册监听器有两种方式, 一种是接口方式, 另一种是注解方式. 这里解析的是实现接口的方式.

在这里,我们要先建立一个印象, 因为后面还会说到他. 为什么呢? 因为接口方式的监听器在两个地方被调用, 一个是这里, 另一个是在refresh()后面的流程registerListener()的时候. 那么, 为什么要有两次调用监听器呢? 我们后面再说

2.4 postProcessBeanFactory(beanFactory); 这是一个扩展方法, 可以初始化剩余的Aware.

我们是AbstractApplicationContext没有实现, 但AbstractRefreshableWebApplicationContext类. 里面就定义了postProcessBeanFactory(beanFactory)
在里面注册了ServletContextAwareProcessor
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
上面我们知道在 BeanFactory 里定义了需要调用的很多Aware. 但是有几个Aware还没有说到.
比如: ServletContextAware's {@code setServletContext} : ServletContextAware, 可以获得当前的ServletContextAware
添加了这个Aware以后, 我们就可以实现一个ServletContextAware的接口.
到这里, 我们就知道所有的aware都在哪里被调用了.

2.5 调用bean工厂的后置处理器, 解析配置类

这一步就略过了,之前重点说过这一步

2.6 registerBeanPostProcessors(beanFactory); 注册bean后置处理器, 这里主要是和AOP有关系

这里和监听器关系不太大, 也暂时略过

2.7  initMessageSource(); 初始化国际化资源处理器

2.8 initApplicationEventMulticaster();创建事件多播器

事件多播器管理所有的事件监听器. 并广播事件给对应的监听器

当我们调用ctx.publishEvent(new OrderEvent(order, "减库存"))的时候. 就会去通知所有监听了OrderEvent事件的事件监听器,
那么, 是由谁去负责通知呢? 就是由EventMulticaster(事件多播器)将事件播报出去的.

首先, 判断有没有最定义的事件多播器. 如果有, 那么直接将其添加到容器中. 如果没有, 就新建一个SimpleApplicationEventMulticaster类型的事件多播器, 然后将其添加到beanFactory中.

那么, 事件多播器都做了什么事情呢? 具体来看一看SimpleApplicationEventMulticaster类.

这是SimpleApplicationEventMulticaster的继承结构. 继承了AbstractApplicationEventMulticaster, 而AbstractApplicationEventMulticaster又实现了ApplicationEventMulticaster. 我们看看在ApplicationEventMulticaster中都对应了哪些接口

public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> listener);
void addApplicationListenerBean(String listenerBeanName);
void removeApplicationListener(ApplicationListener<?> listener);
void removeApplicationListenerBean(String listenerBeanName);
void removeAllListeners();
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}

看名字就知道了, 做了两件事, 一个是管理事件监听器, 另一个是广播事件.

我们看AbstractApplicationEventMulticaster如何实现这几个接口的

/**
* AbstractApplicationEventMulticaster管理了所有的监听器.
* 当我们注册一个监听器以后, 就会通过addApplicationListener方法添加到事件多播器中.
* @param listener the listener to add
*/
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}

这是添加事件监听器.

在SimpleApplicationEventMulticaster里面, 定义了广播事件监听器

@Override
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
);
}
}
}

这里有两种方式, 一种是同步的方式, 另一种是异步的方式. 根据设置的eventType来决定的. 其实异步的方式就是建立了一个新的线程

我么你来看一下调用事件监听器广播事件

invokeListener#doInvokeListener

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 最终调用的是监听器的onApplicationEvent方法. 这个方法就是每一个监听器都会自定义的方法.
listener.onApplicationEvent(event
);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
最终调用的是监听器的onApplicationEvent方法. 这个方法就是每一个监听器都会自定义的方法.
listener.onApplicationEvent(event);

2.9 onRefresh();这是一个扩展方法. 这里没有具体实现.spring boot也是从这个方法进行启动

2.10 注册监听器registerListeners();

注册监听器这里一共做了三件事:

这里做了几件事:

1. 将事件监听器注册到多播器上

2. 广播早期的事件

3. 清空早期事件.

到此步骤之前, 上面都是有早期事件的, 后面就没有早期事件了,因为这一步就都清空了. 后面也不会在进行自动广播了, 自动广播的就是早期事件.

protected void registerListeners() {
// Register statically specified listeners first.
/**
* 第一步, 获取所有的事件监听器集合.
* 通常, 这个时候, 事件监听器集合是空的, 除非手动调用allApplicationListeners()注册事件监听器
*/

for (ApplicationListener<?> listener : getApplicationListeners()) {
// 将监听器注册到多播器上
getApplicationEventMulticaster().addApplicationListener(listener);
} /**
* 第二步: 注册接口方式的监听器
* 获取beanDefinition中 ApplicationListener 类型的监听器. 也就是说, 使用接口方式定义的监听器就可以在这里被注册到多播器的
* 这里是从BeanDefinition中拿的, 我们自定义了 OrderEventListenter 监听器, 那么会不会拿到呢?
* 我们知道监听器的实现有两种方式, 一种是接口方式, 一种是注解方式.
* 如果OrderEventListenter采用的是接口方式, 那么就可以拿到. 因为它实现了ApplicationListener.拿到了, 就把监听器注册到多播器上.
* 如果是注解方式, 那就拿不到了
*
*/
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 把监听器注册到多播器上
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
} /**
* 第三步: 获取早期的事件, 然后广播早期事件.
* 这些早期事件是在第一步 prepareRefresh 注册的.
*
*/

Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
// 在这里将早期事件清空, 清空完以后, 就没有早期事件了.
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

如上源码所示:

第一步. 获取所有的事件监听器集合, 通常这个时候, 事件监听器的集合都是空的, 除非我们手动调用allApplicationListeners()注册事件监听器

第二步: 注册接口方式的监听器. 注意,是接口方式的. 通常我们自定义的监听器.  有两种类型, 接口方式和注解方式. 如果使用的是接口方式. 那么就是在这里被注册的.如果是注解方式.不在这里注册.

getBeanNamesForType(ApplicationListener.class, true, false);
扫描获取ApplicationListener类型的监听器.

然后将其注册到多播器上. 我们知道多播器的两个主要功能, 管理监听器和广播事件.

getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

第三步: 获取早期事件, 然后广播早期事件. 早期事件我们之前已经说过了, 是在第一步prepareRefresh()方法里注册的.

随后, 立即清空早期事件集合. 然后广播事件. 这样早期定义好的事件就都被广播出去了, 并且只能执行一次, 不会被再次执行.

/**
* 第三步: 获取早期的事件, 然后广播早期事件.
* 这些早期事件是在第一步 prepareRefresh 注册的.
*
*/
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
// 在这里将早期事件清空, 清空完以后, 就没有早期事件了.
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}

2.11 实例化剩余的单实例bean

这个方法就是循环遍历BeanDefinitionMap, 调用getBean, 去生产剩余的bean, 之前详细研究过这个步骤, 这里就不说了

2.12 完成refresh()操作, 发布刷新事件

protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 清除上下文缓存
clearResourceCaches(); // Initialize lifecycle processor for this context.
// 注册lifecycleProcessor声明周期处理器
// 作用: 当ApplicationContext启动或停止时, 他会通过LifecycleProcessor来与所有声明的bean进行交互
initLifecycleProcessor(); // Propagate refresh to lifecycle processor first.
// 为实现了SmartLifeCycle并且isAutoStartup, 自动启动的Lifecycle调用start()方法
getLifecycleProcessor().onRefresh(); // Publish the final event.
// 发布容器refresh完毕的事件.
// 发布的是什么事件呢? 是ContextRefreshedEvent事件.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

在这一步: 发布了容器Refreshed事件. 也就是容器启动完成的事件.

到这里, 我们来看看publicshEvent的具体实现

/**
* 发布事件给所有的监听器
* Publish the given event to all listeners.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* @param eventType the resolved event type, if known
* @since 4.2
*/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent; /**
* 第一步: 获取事件
*/

if (event instanceof ApplicationEvent) {
// 处理接口类型的事件
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
} /**
* 第二步: 发布事件
*/

// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
/*
*调用事件多播器, 将这个事件发布出去
* 事件多播器是什么时候注册的呢? 就是在refresh()初始化的时候, 调用initApplicationEventMulticaster(); 初始化的事件多播器
*/
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

} /**
* 第三步: 发布事件给父类容器
*/

// Publish event via parent context as well...
// 发布事件给父类容器
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}

这里做了如下几件事

1. 获取事件

2. 广播事件

3. 广播事件给父类监听器.

详细代码可以看注释

接下来看一下,具体的multicastEvent(...)

@Override
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);
}
}
}

这里首先会去获取线程池. 看看有没有重新定义线程池, 如果有这里executor就不是空的.

广播事件有两种形式, 一种是同步, 一种是异步. 如果executor线程池不空, 就以异步的形式广播, 否则就以同步的形式广播.

那么,我们如何自定义同步或者异步呢? 也是有两种方式

第一种方式: 自定义事件多波器, 并指定taskExcutor

  @Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster
= new SimpleApplicationEventMulticaster(); //ThreadPoolTaskExecutor
// 这里指定了 taskExecutor, 就会使用异步的方式去执行
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}

第二种方式, 在事件监听器上使用注解@Async

@Component
@Async
public class OrderEventListenter implements ApplicationListener<OrderEvent> {
/**
* 当某一个事件发布的时候, 就会触发事件监听器
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(OrderEvent event) {
if (event.getName().equals("减库存")) {
System.out.println("事件监听器 监听到 减库存");
}
}
}

接下来看看如何广播事件的.

/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 最终调用的是监听器的onApplicationEvent方法. 这个方法就是每一个监听器都会自定义的方法.
listener.onApplicationEvent(event
);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}

其实,具体执行的逻辑, 就是我们在监听器中定义的onApplicationEvent(event)方法中的逻辑实现.

三. 注册接口方式的监听器

在上面的源码分析中, 注册接口方式的监听器, 其实是由两个地方.

第一个: 在第十步registerListener()

protected void registerListeners() {
.....
/**
* 第二步: 注册接口方式的监听器
* 获取beanDefinition中 ApplicationListener 类型的监听器. 也就是说, 使用接口方式定义的监听器就可以在这里被注册到多播器的
* 这里是从BeanDefinition中拿的, 我们自定义了 OrderEventListenter 监听器, 那么会不会拿到呢?
* 我们知道监听器的实现有两种方式, 一种是接口方式, 一种是注解方式.
* 如果OrderEventListenter采用的是接口方式, 那么就可以拿到. 因为它实现了ApplicationListener.拿到了, 就把监听器注册到多播器上.
* 如果是注解方式, 那就拿不到了
*
*/
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 把监听器注册到多播器上
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

.....
}

另一个: 是在第三步进行属性填充的时候注册的

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
......
/**
* 注册事件监听器探测器后置处理器接口, ApplicationListenerDetector 解析接口方式的监听器
*/
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this
)); ......
}

在准备属性的方法里, 有一个注册时间监听器探测器后置处理. 在这个监听器的探测器里面, 进行了注册.

来看看ApplicationListenerDetector

class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {

    ....../**
* 初始化后的bean后置处理器
*
* 这个方法是在 registerListener 之后执行的, 在registerListener()方法里注册过一次接口方式的监听器.
* 在这里还会在注册一次.
*
* 问题: 为什么同一个监听器, 要在两个地方注册呢?
* 第一次添加的是监听器的名字, 第二次添加的是bean实体. 那为什么要添加两次呢?
* 这是为了处理带有@Lazy懒加载方式的bean. 懒加载的bean是不会在初始化容器的时候创建bean的.
*
* 比如, 我给监听器类加上一个@Lazy, 那么他就不会走bean的后置处理器, 因为bean的后置处理器, 是在bean创建过程中调用的.
* 那什么时候会被调用呢? 在真正使用的时候. 比如调用 ctx.publishEvent(new OrderEvent(order, "减库存"));
* 马上就要用到了, 所以, 这时候回去调bean的后置处理器. 执行代码看一下效果
*
*
* @param bean the new bean instance
* @param beanName the name of the bean
* @return
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
/*
* 注册接口类型的监听器. 将其添加到applicationContext中
* 之所以要在这里在加一次, 是为了处理懒加载情况
*/
this.applicationContext.addApplicationListener((ApplicationListener<?>
) bean);
}
else if (Boolean.FALSE.equals(flag)) {
// 这里是处理早期事件.
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
.......
}

我们看到在ApplicationListenerDetector中定义了方法postProcessAfterInitialization. 这个方法会在创建属性的第三步执行完以后调用. 第三步是初始化. 看名字也知道是初始化之后调用的后置处理器. 在这里, 注册了接口类型的监听器

this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);

那么, 为什么要有两次注册呢?

其实这里是为了解决懒加载的问题. 因为,如果一个类是懒加载的类, 那么他只有真正被调用的时候才回去加载. 所以, 也就是在类进行初始化以后才会被调用. 因此在初始化之后再次加载了接口类型的监听器.

四. 解析注解方式的监听器

整个流程走完, 我们都只看到接口方式的监听器注册的地方. 那么注解类型的监听器是什么时候被创建的呢?

首先, 注解是何时被解析的? 我们知道BeanDefinitionReader在解析创世纪的类的时候, 注册了很多创世纪的类.其中就有两个是用于负责处理@EventListener注解的

再来回顾一下这段代码

public static Set<BeanDefinitionHolder>  registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) { // 获取到beanFactory
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
/**
* 判断beanFactory中是否有AnnotationAwareOrderComparator和ContextAnnotationAutowireCandidateResolver
* 没有则添加
*/
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
} // BeanDefinitionHolder: 为BeanDefinition设置名字和别名
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // 如果registry中没有ConfigurationClassPostProcessor配置类后置处理器, 就添加一个
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
// 构建BeanDefinitionHolder, 并添加到beanDefs
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
} // 如果rigistry中, 没有AutowiredAnnotationBeanPostProcessor Autowired注解bean的后置处理器, 则添加一个
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
// 构建BeanDefinitionHolder, 并添加到beanDefs
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
} // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
// 检查对JSR-250的支持, 如果rigistry中没有 CommonAnnotationBeanPostProcessor 通用注解后置处理器, 则添加一个
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
// 构建BeanDefinitionHolder, 并添加到beanDefs
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
} // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
// 检查对jpa的支持, 如果不包含 internalPersistenceAnnotationProcessor, 持久化注解处理器, 就添加一个
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
} /**
* 下面这两个注解是用来解析@EventListener的
*/

// 检查对事件监听的支持, 如果不包含事件监听处理器 internalEventListenerProcessor, 就添加一个
/*
* EventListenerMethodProcessor : 既不是bean的后置处理器, 也不是bean工厂的后置处理器
* 那么EventListenerMethodProcessor是在哪里被调用,并且解析注解方式的监听器呢?
*
* 下面看一下EventListenerMethodProcessor的继承结构图.
* 1. 实现了SmartInitializingSingleton接口 :
* 2. 实现了ApplicationContextAware接口 : 因为要往容器中注入bean, 所以,里面要使用容器的上下文, 将容器以Aware的方式set进来
* 3. 实现了BeanFactoryPostProcessor接口 :
*
*
*/
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
} // 如果不包含事件监听工厂处理器 internalEventListenerFactory , 就添加一个
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
} return beanDefs;
}

如上图就是注册的创世纪的处理器. 最后两个就是用来处理@EventListener注解的.

下面来看看EventListenerMethodProcessor事件监听器处理器,

首先, 看一下EventListenerMethodProcessor的继承结构图.

EventListenerMethodProcessor实现了三个接口.

1.实现了SmartInitializingSingleton接口

2. 实现了ApplicationContextAware接口 : 因为要往容器中注入bean, 所以,里面要使用容器的上下文, 将容器以Aware的方式set进来

3. 实现了BeanFactoryPostProcessor接口

SmartInitializingSingleton接口在哪里被用到了呢?

在refresh()#finishBeanFactoryInitialization(beanFactory); 实例化剩余的单例bean的过程中

在DefaultListableBeanFactory#preInstantiateSingletons()方法. 有两次循环遍历beanNames

@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
} // Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 获取容器中所有bean定义的名字
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans...
/**
* 第一步: 循环bean定义的name, 创建bean
*/

for (String beanName : beanNames) {
// 获取bean定义
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 生产bean定义的条件: 不是抽象的, 是单例的, 不是懒加载的. 符合这个标准的, 最后才会调用getBean()生产bean
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 这里判断是不是工厂bean, 这里和BeanFactory不是一个意思, 判断当前这个bean是否实现了beanFactory的接口
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
// 将bean转换为FactoryBean 工厂bean
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
} if (isEagerInit) {
// 获取bean
getBean(beanName);
}
}
}
else {
// 第二步: 调用getBean
getBean(beanName);
}
}
} // Trigger post-initialization callback for all applicable beans...
/**
* 第二步: 循环bean定义的name, 解析是否有实现了SmartInitializingSingleton接口的类
* 到这里, bean都已经被创建完了
*/

for (String beanName : beanNames) {
// 从缓存中得到实例instance
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}

第一次循环, 是创建bean, 并获取bean

第二次循环, 是在所有的bean都已经创建完以后, 如果singletonInstance是SmartInitializingSingleton的实例, 则调用afterSingletonsInstantiated()方法.

以下是EventListenerMethodProcessor#afterSingletonsInstantiated()方法实现

@Override
public void afterSingletonsInstantiated() {
// 从spring容器中获取EventListenerFactoryBean
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
// 获取所有类型的bean
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}

这里主要看processBean(beanName, type) 处理bean

private void processBean(final String beanName, final Class<?> targetType) {
// 1. 是否包含注解@EventListener
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) { Map<Method, EventListener> annotatedMethods = null;
try {
// 2. 查找@EventListener注解, 如果有则拿到标注@EventListener的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
} if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set"); // 3. 获取bean工厂. 这个bean工厂是我们在创世纪的时候注册的EventListenerFactory
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
// 4. 循环遍历有注解的方法
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); //5. 创建事件监听器
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
} // 6. 将监听器注入到多播器中
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}

1. 首先判断, 是否包含@EventListener注解

2. 查找@EventListener注解, 如果有则拿到标注@EventListener的方法

3. 获取bean工厂. 这个bean工厂是我们在创世纪的时候注册的EventListenerFactory

4. 循环遍历有注解的方法

5. 创建事件监听器

6. 将监听器注入到多播器中

以上就是注解版的监听器是如何注入到多播器中的.

五. 怎样在所有的bean都创建完以后做扩展代码?

第一种方式, 添加内置的监听器, 类加载完以后, 调用监听器

第二种方法. 就是在使用注解方式的时候,  实现SmartInitializingSingleton接口. 然后在bean实例化完成以后, 在调用

4.1 Spring源码 --- 监听器的原理的更多相关文章

  1. Spring源码系列 — 注解原理

    前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...

  2. Spring源码之@Configuration原理

    总结 @Configuration注解的Bean,在BeanDefinition加载注册到IOC容器之后,进行postProcessBeanFactory处理时会进行CGLIB动态代理 将@Prope ...

  3. Spring源码 03 IOC原理

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  4. Spring源码:IOC原理解析(一)

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! IOC(Inversion of Control),即控制反转,意思是将对象的创建和依赖关系交给第三方容器处理,我们要用的时候告诉容器我们 ...

  5. Spring源码:IOC原理解析(二)

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 接着上一章节的内容,我们来分析当new一个FileSystemXmlApplicationContext对象的时候,spring到底做了那 ...

  6. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

  7. Spring 源码分析之 bean 实例化原理

    本次主要想写spring bean的实例化相关的内容.创建spring bean 实例是spring bean 生命周期的第一阶段.bean 的生命周期主要有如下几个步骤: 创建bean的实例 给实例 ...

  8. Spring Boot 揭秘与实战 源码分析 - 工作原理剖析

    文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...

  9. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...

随机推荐

  1. zookeeper核心之ZAB协议就这么简单!

    背景 我们都知道 Zookeeper 是基于 ZAB 协议实现的,在介绍 ZAB 协议之前,先回顾一下 Zookeeper 的起源与发展. Zookeeper 究竟是在什么样的时代背景下被提出?为了解 ...

  2. 由反转链表想到python链式交换变量

    这两天在刷题,看到链表的反转,在翻解体思路时看到有位同学写出循环中一句搞定三个变量的交换时觉得挺6的,一般用的时候都是两个变量交换(a,b=b,a),这种三个变量的交换还真不敢随便用,而且这三个变量都 ...

  3. Deployer 的使用

    假设我们的项目在本地 /www/demo-project 下,那么我们切换到该目录: $ cd /www/demo-project 然后执行 Deployer 的初始化命令: $ dep init 它 ...

  4. 赛门铁克和DigiCert证书有什么区别?

    在众多国人眼里,赛门铁克Symantec名气更胜于DigiCert证书.但是,我们知道2017年赛门铁克因一系列原因被DigiCert收购,品牌名称也被更新为DigiCert Secure Site. ...

  5. D. Alyona and Strings 解析(思維、DP)

    Codeforce 682 D. Alyona and Strings 解析(思維.DP) 今天我們來看看CF682D 題目連結 題目 略,請直接看原題. 前言 a @copyright petjel ...

  6. Luogu P3602 Koishi Loves Segments

    传送门 题解 既然是选取区间,没说顺序 肯定先排遍序 都是套路 那么按什么排序呢??? 为了方便处理 我们把区间按左端点从小到大排序 把关键点也按从小到大排序 假设当扫到 \(i\) 点时,i 点之前 ...

  7. 在pandas中使用pipe()提升代码可读性

    1 简介 我们在利用pandas开展数据分析时,应尽量避免过于碎片化的组织代码,尤其是创建出过多不必要的中间变量,既浪费了内存,又带来了关于变量命名的麻烦,更不利于整体分析过程代码的可读性,因此以流水 ...

  8. SpringBoot第五集:整合Druid和MyBatis(2020最新最易懂)

    SpringBoot第五集:整合Druid和MyBatis(2020最新最易懂) 1.SpringBoot整合Druid Druid是阿里巴巴的一个开源项目,是一个数据库连接池的实现,结合了C3P0. ...

  9. 4、Python语法之变量

    一 引入 我们学习Python语言是为了控制计算机.让计算机能够像人一样去工作,所以在Python这门语言中,所有语法存在的意义都是为了让计算机具备人的某一项技能,这句话是我们理解后续所有Python ...

  10. day87:luffy:结算页面积分&支付宝接口

    目录 1.积分 2.支付 1.积分 1.关于积分的表结构 1.在user表中添加credit字段 + 设计一个积分的表结构 user/models.py class User(AbstractUser ...