Spring Bean 的生命周期
参考源码及网络资料的个人学习笔记,欢迎大家指正错误。
源码版本`SpringBoot-2.7.2`
大致的生命周期概括
大体过程为: 实例化 --》 属性赋值 --》 初始化 --》 销毁,但在其中涉及复杂的过程及细节:
-
启动spring容器,创建beanFactory,用来创建与管理Bean。一般用的是Applicationcontext(
ApplicationContext
是BeanFactory
的子接口,它继承了BeanFactory
的功能,并且提供了更多的企业级功能,如国际化支持、事件发布、AOP、事务管理等)然后通过
Applicationcontext
加载配置文件,或者利用注解扫描的方式将bean的配置信息加载到spring容器里面。 -
加载之后,spring容器会将这些配置信息(java bean的信息),根据不同的配置方式,封装成
BeanDefinition
对象。 -
然后将这些
BeanDefinition
对象以key为beanName,值为BeanDefinition
对象的形式存入到一个map里面,将这个map传入到spring beanfactory
去进行springBean的实例化。 -
进入实例化阶段,先在实例化之前执行
InstantiationAwareBeanPostProcessor
接口的postProcessBeforeInstantiation
方法,做springBean实例化之前的扩展 -
调用
SmartInstantiationAwareBeanPostProcessor
接口的determineCandidateConstructors
方法,确定实例化bean要使用的构造函数。 -
通过构造函数来创建bean实例,也就是进行实例化。
-
实例化之后,调用
MergedBeanDefinitionPostProcessor
接口的postProcessMergedBeanDefinition
方法,对BeanDefinition
进行扩展修改。spring中已包括:处理自动装配注解(如
@Autowired
、@Value
等)、处理通用注解(如@Resource
、@PostConstruct
、@PreDestroy
等)、处理bean的初始化及销毁相关(如**@PostConstruct
** 和 **@PreDestroy
**等)、处理@Scheduled
及@Required
注解等。主要是将这些注解对应的处理信息修改到bean定义中,用于后续生效。 -
调用
SmartInstantiationAwareBeanPostProcessor
的getEarlyBeanReference
方法,获取一个早期的、还没有进行属性赋值和初始化的bean,缓存起来用于解决循环依赖的问题。 -
接下来马上进行属性赋值阶段,调用
InstantiationAwareBeanPostProcessor
的postProcessAfterInstantiation
方法,做bean属性赋值之前的扩展操作,或自定义实现属性赋值逻辑。 -
调用
InstantiationAwareBeanPostProcessor
的postProcessProperties
方法,在Bean属性赋值之前对Bean的属性值进行进一步的定制和修改。 -
在AbstractAutowireCapableBeanFactory 类中的
populateBean
方法中调用applyPropertyValues
方法,进行属性赋值,将给定的属性值应用到指定的 bean 中。 -
属性赋值完成后,进入初始化之前的阶段,调用
BeanPostProcessor
的postProcessBeforeInitialization
方法,允许开发者在Bean初始化之前对Bean进行自定义的处理操作。现有实现包括:ApplicationContext上下文配置、初始化之前的bean验证、引导Spring应用程序的上下文注入、
@ConfigurationProperties
注解处理、@Import
注解的处理、错误页配置等。 -
正式进行bean初始化,在
AbstractAutowireCapableBeanFactory
类中调用afterPropertiesSet
方法。不同的bean初始化逻辑不同。 -
调用
BeanPostProcessor
的postProcessAfterInitialization
方法,进行bean初始化后的扩展操作。spring现有的实现包括:aop动态代理创建、bean初始化后的验证、
@Scheduled
定时任务的创建执行等。 -
执行
registerDisposableBeanIfNecessary
方法,如果bean有销毁方法,将bean注册为可销毁bean,即在容器关闭后会调用bean的销毁方法。 -
调用
SmartInitializingSingleton
的afterSingletonsInstantiated
方法,在所有单例 bean 初始化完成后再进行一些特定的扩展操作,可自定义进行扩展。现有spring实现包括:创建缓存管理及解析器,提供缓存功能的支持;提供在非spring环境下,创建与调度定时任务;注册事件监听器;创建MBean,实现对 Spring 管理的 bean 的监控和管理功能。
BeanDefinition
先介绍bean定义,因为先有BeanDefinition,然后才有bean
简介
在我们通过注解、xml
或其他配置方式
编写bean后,spring在启动时会扫描这些配置, 生成BeanDefinition
,并用其来构建出这些bean。所以说,Spring是根据BeanDefinition
来创建Spring bean
的。
BeanDefinition
是一个接口:
在BeanDefinition
的代码中,包含bean定义的相关属性,如bean的类名、作用域、是否懒加载、依赖关系
等:
-
getBeanClassName()
- 获取Bean的类名 -
getScope()
- 获取Bean的作用域 -
isSingleton()
/isPrototype()
- 判断是否单例/原型作用域 -
getInitMethodName()
- 获取初始化方法名 -
getDestroyMethodName()
- 获取销毁方法名 -
getLazyInit()
- 获取是否延迟初始化 -
getDependsOn()
- 获取依赖的Bean -
getPropertyValues()
- 获取属性值 -
getAutowireCandidate()
- 获取是否可以自动装配 -
getPrimary()
- 获取是否首选的自动装配Bean
创建
BeanDefinition
的源码位置
主启动类的run
方法,调用SpringApplication类中run
方法里面的如下代码:
this.refreshContext(context);
点击上面的refreshContext
,一路进入refresh
方法直到AbstractApplicationContext类的refresh
方法,调用其中的:
invokeBeanFactoryPostProcessors(beanFactory);
进入其中再到:
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
invokeBeanFactoryPostProcessors
方法中便涉及到了BeanDefinitionRegistry
来注册BeanDefinition
BeanDefinition的类型及其应用
在Spring
中,一个bean
的配置信息是由BeanDefinition
对象来保存的。根据bean
配置的不同来源和方式,BeanDefinition
又被分为很多种类型,BeanDefinition
是父接口:
下面介绍几种实现:
RootBeanDefinition
对应xml配置的bean
。
<bean id="testBean" class="com.example.testBean">
<property name="testProperty" value="testValue"/>
</bean>
其中id标签是bean名字,class标签是bean的类(BeanClassName
),property则对应属性值PropertyValues
ChildBeanDefinition
当我们需要让一个bean
继承另一个bean
的配置时,可以使用ChildBeanDefinition
。例如:
<bean id="parentBean" class="com.example.ParentBean">
<property name="testProperty" value="testValue"/>
</bean>
<bean id="childBean" parent="parentBean">
<property name="oneTherTestProperty" value="oneTestValue"/>
</bean>
为"parentBean"
创建一个RootBeanDefinition
对象,然后为"childBean"
创建一个ChildBeanDefinition
对象,这个对象通过parent
标签引用"parentBean"
的BeanDefinition
。
GenericBeanDefinition
通用的 BeanDefinition
实现类,可以用于注解、包扫描等配置方式。
AnnotatedBeanDefinition
当我们在代码中使用注解(如@Component
, @Service
, @Repository
等)来定义bean
时,Spring
会创建一个AnnotatedBeanDefinition
接口的实例。
ScannedGenericBeanDefinition
用于扫描包配置方式,通过扫描指定包路径下的类并解析类上的注解来定义和配置 bean。
Bean的创建
源码入口
主启动类的run
方法,调用到SpringApplication类中run
方法里面的如下代码:
refreshContext(context);
进入上面的refreshContext
方法里面,进入其中的refresh
,一直到AbstractApplicationContext类的refresh
方法,调用其中的:
finishBeanFactoryInitialization(beanFactory);
在finishBeanFactoryInitialization
中看到:
beanFactory.preInstantiateSingletons();
进入其中,到达 DefaultListableBeanFactory 类中 preInstantiateSingletons
方法内的getBean
:
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
getBean
再调用AbstractBeanFactory 中 getBean
方法的 doGetBean
方法:
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
doGetBean
方法调用 AbstractAutowireCapableBeanFactory 的 createBean
方法中的
doCreateBean
doCreateBean
中就是Bean的创建逻辑
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化阶段
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...//省略
Object exposedObject = bean;
try {
//属性赋值阶段
populateBean(beanName, mbd, instanceWrapper);
//初始化Bean阶段
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
........//省略
}
//处理循环依赖
if (earlySingletonExposure) {
........//省略
}
// 注册bean在容器关闭时的销毁方法
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}......//省略
//返回bean
return exposedObject;
}
下面开始正式介绍bean生命周期流程
Bean的实例化:
Bean实例化之前
1.postProcessBeforeInstantiation
InstantiationAwareBeanPostProcessor
接口的postProcessBeforeInstantiation
方法
作用:对springBean做实例化之前的扩展,可由开发者自定义实现
-
如果是配置的非合成bean,并且有
InstantiationAwareBeanPostProcessor
接口的postProcessBeforeInstantiation
方法实现,那么就执行此方法,做bean实例化前扩展。 -
如果是spring内部生成的bean,就跳过不执行此方法
需要注意的是,如果postProcessBeforeInstantiation
方法返回的bean不为null,后续的bean实例化、初始化就不执行了。
源码
位于AbstractAutowireCapableBeanFactory 的 createBean
方法中,在 doCreateBean
创建bean之前,会执行:
//给BeanPostProcessors一个返回代理、而不是返回目标bean实例的机会。
//参数为BeanName和BeanDefinition,
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
进入上面所示的resolveBeforeInstantiation
方法中,看到applyBeanPostProcessorsBeforeInstantiation
方法,在它里面调用了 InstantiationAwareBeanPostProcessor 后置处理器
接口的 postProcessBeforeInstantiation
方法:
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
//beforeInstantiationResolved 属性用于表示一个 bean 在实例化之前是否已经进行了方法重写解析。
//方法重写可以在 Spring 容器中使用 lookup-method 和 replaced-method 元数据进行定义。
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
/**
* 判断是不是合成bean,以及是否有BeanPostProcessor的实现
* isSynthetic():用来判断Bean定义是否为合成Bean的。
* 1.合成Bean是指一种通过编程方式在Spring容器中创建的bean,是在运行时由容器生成的Bean(返回true),往往不会触发完整的生命周期回调和后置处理器的执行
* 2.非合成Bean是指通过XML配置、Java配置(如@Configuration类)或组件扫描等方式创建和定义的bean。会触发所有的生命周期回调和后置处理器的执行
*
* 当bean不是合成bean,并且有`InstantiationAwareBeanPostProcessor`接口的实现,就进入if执行bean实例化前的扩展方法
* */
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
//调用实例化前`postProcessBeforeInstantiation` 方法
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
//bean不为空,则说明我们自定义实现了实例化前置方法,此处设置其为true
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
关于上面
mbd.beforeInstantiationResolved
属性
beforeInstantiationResolved
是RootBeanDefinition
类的属性,用于表示一个 bean 在实例化之前是否已经进行了方法重写解析。
方法重写可以在 Spring 容器中使用 lookup-method
和 replaced-method
元数据进行定义。
lookup-method和replaced-method是在xml配置bean的时候的可选配置:
-
lookup-method
可以声明方法返回某个特定的bean。 -
replaced-method
可以改变某个方法甚至是改变方法的逻辑。
例如:
<?xml version="1.0" encoding="UTF-8"?>
<bean id="demoA" name="demoA" class="com.example.springbootdemo.property.DemoA">
<!-- 指定 DemoA.getDemoBase 方法,返回值是 容器中的demoC -->
<lookup-method name="getDemoBase" bean="demoC"></lookup-method>
<!-- 指定 DemoA.hello方法,其方法经过 demoMethodReplacer.reimplement 代理,
相当于执行 DemoA.hello 方法其实是执行 demoMethodReplacer.reimplement 方法 -->
<replaced-method name="hello" replacer="demoMethodReplacer"></replaced-method>
</bean>
<bean id="demoB" name="demoB" class="com.example.springbootdemo.property.DemoB"></bean>
<bean id="demoC" name="demoC" class="com.example.springbootdemo.property.DemoC"></bean>
<bean id="demoMethodReplacer" name="demoMethodReplacer" class="com.example.springbootdemo.property.DemoMethodReplacer"></bean>
</beans>
如果
postProcessBeforeInstantiation
方法返回的bean不为null,后续的bean实例化、初始化就不执行了:
原因是,因为这个方法提供了一种在实例化之前就能够完全控制bean对象的机会。如果在这个方法中返回了非空的bean对象,Spring容器会认为返回的对象是已经实例化好的,将跳过后续的实例化和初始化过程。
2.determineCandidateConstructors
这个方法的作用,就是确定使用哪个构造函数来实例化Bean。如果bean是需要用构造函数来进行注入的,就用其注入的有参构造函数实例化。如果没有,就用默认的无参构造实例化
SmartInstantiationAwareBeanPostProcessor
接口的determineCandidateConstructors
方法
在AbstractAutowireCapableBeanFactory 的 doCreateBean
创建bean的方法中,会执行:
instanceWrapper = createBeanInstance(beanName, mbd, args);
来创建Bean实例,而其中又调用了
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
进而调用了
SmartInstantiationAwareBeanPostProcessor
接口的 determineCandidateConstructors
方法:
determineCandidateConstructors
这个方法是在 Bean 实例化之前的阶段执行的,主要是获取并确定要使用的构造函数。
- 首先,通过判断
beanClass
是否为空,并且是否存在InstantiationAwareBeanPostProcessors
(即实现了InstantiationAwareBeanPostProcessor
接口的后置处理器)来确定是否需要进行处理。 - 如果
beanClass
不为空且存在InstantiationAwareBeanPostProcessors
,则遍历这些后置处理器,对于每个实现了SmartInstantiationAwareBeanPostProcessor
接口的后置处理器bp
,调用其determineCandidateConstructors(beanClass, beanName)
方法来获取候选的构造函数数组ctors
。 - 如果
ctors
不为空,则说明找到了合适的构造函数,直接返回ctors
。如果没有找到合适的构造函数,则返回null
,表示无法确定构造函数。
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName) throws BeansException {
//如果 `beanClass` 不为空且存在 `InstantiationAwareBeanPostProcessors`后置处理器
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
//则遍历这些后置处理器
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
//获取候选的构造函数数组
Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
return null;
}
总结起来,这段代码的作用是通过后置处理器来确定要使用的构造函数。
然后再看AbstractAutowireCapableBeanFactory 的
doCreateBean
,看创建bean实例的方法createBeanInstance
是如何调用determineCandidateConstructors
来使用构造函数的
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
//省略前面部分
.........
// 确定候选构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
//判断是否需要通过构造函数来进行autowire自动装配
//从前到后的条件依次是:存在候选构造函数、通过配置指定了自动装配需要使用构造函数进行、bean定义中是否存在构造函数参数值、构造函数参数的数组不为空
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//如果上述条件满足,将会调用autowireConstructor方法使用自动装配来创建bean实例。
return autowireConstructor(beanName, mbd, ctors, args);
}
//获取通过配置指定的首选构造函数。
ctors = mbd.getPreferredConstructors();
//如果存在首选构造函数,将会调用autowireConstructor方法使用首选构造函数进行自动装配,来创建bean实例。
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
//如果上述条件都不满足,将会调用instantiateBean方法使用无参构造函数来创建bean实例。
return instantiateBean(beanName, mbd);
}
这段代码片段主要是根据不同情况来选择适当的构造函数来创建bean实例。当需要使用构造函数来进行autowire
自动装配的话,就通过有参构造函数进行bean实例创建,否则就使用无参构造函数创建bean实例
所以最终,SmartInstantiationAwareBeanPostProcessor
接口的 determineCandidateConstructors
方法就是用来确定实例化Bean要使用哪个构造方法。
额外补充,
SmartInstantiationAwareBeanPostProcessor
的其他方法
predictBeanType
方法的作用:predictBeanType
方法用于预测Bean的类型(Class),即在实例化Bean之前能够提前确定Bean的类型。这个方法可以用于解决一些特殊情况下的类型推断问题,例如在泛型中无法确定具体类型的情况下,可以通过这个方法来明确推断类型。getEarlyBeanReference
方法的作用:getEarlyBeanReference
方法用于提前暴露Bean的引用。在Bean实例化的早期阶段,如果某些Bean需要在其他Bean实例化之前就被引用,可以通过这个方法提前暴露出来,以满足这些依赖关系。后面还会介绍这个方法。
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
//预测Bean的类型(Class)
@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
//确定构造函数,上面介绍了不多说
@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
throws BeansException {
return null;
}
//提前暴露Bean的引用
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
}
这两个方法通常在AbstractAutowireCapableBeanFactory
类中被调用,用于在Bean实例化的过程中对Bean进行处理。具体来说:
predictBeanType
方法通常在AbstractAutowireCapableBeanFactory
的resolveBeforeInstantiation
方法中被调用,用于在实例化Bean之前预测并获取Bean的类型。getEarlyBeanReference
方法通常在AbstractAutowireCapableBeanFactory
的doCreateBean
方法中,Bean属性赋值之前被调用,用于提前暴露Bean的引用。在下面会说到。
这两个方法都提供了在Bean实例化过程中的扩展点,具体实现可以由开发人员根据具体的需求来提供, 在Bean实例化过程中对类型推断和提前引用进行个性化的处理。
开始Bean实例化
在AbstractAutowireCapableBeanFactory 的
createBeanInstance
方法中
上面的determineCandidateConstructors
代码解析中,如果需要进行构造注入,就用有参构造函数进行实例化,否则就是用无参构造函数实例化。
调用完determineCandidateConstructors
之后,如果需要使用构造函数来进行autowire
注入,就执行autowireConstructor
方法用构造函数来创建实例
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
如果不需要用构造函数来进行autowire
注入,就调用instantiateBean
方法,用默认构造函数来创建bean实例:
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
instantiateBean
方法具体代码:
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
Bean实例化之后
3.postProcessMergedBeanDefinition
MergedBeanDefinitionPostProcessor
接口的postProcessMergedBeanDefinition
方法
在实例化阶段之后,属性赋值阶段之前,调用MergedBeanDefinitionPostProcessor
接口的 postProcessMergedBeanDefinition
方法,用于处理和修改bean定义,处理包括但不限于:修改Bean定义的属性、添加额外的元数据、校验Bean定义等。
- 根据
postProcessMergedBeanDefinition
方法的6个实现(下面会介绍有哪6个),大致有如下相关处理:
处理自动装配注解(如@Autowired
、@Value
等)、处理通用注解(如@Resource
、@PostConstruct
、@PreDestroy
等)、处理bean的初始化及销毁相关(如@PostConstruct
和 @PreDestroy
等)、处理@Scheduled
及@Required
注解等。主要是将这些注解对应的处理信息修改到bean定义中,用于后续生效。
- 需要注意的点:
此阶段存在Autowired
注入处理,但是没有真正的执行注入,而在下一步Bean的属性赋值阶段进行注入,此处只是通过AutowiredAnnotationBeanPostProcessor
实现来查找和筛选需要注入的属性,并缓存到Bean定义中,也正是对应了用于处理和修改bean定义的作用
源码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化阶段
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
.........
/**
* 允许后处理程序修改合并后的bean定义。
*/
//获取同步的锁对象,它是RootBeanDefinition类中的一个成员变量(或属性)
synchronized (mbd.postProcessingLock) {
//判断是否已经对合并后的Bean定义进行过后置处理。如果postProcessed属性为false,说明还未进行过后置处理,就进入if。
if (!mbd.postProcessed) {
try {
//此处调用了postProcessMergedBeanDefinition方法
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
//最后,将postProcessed属性设置为true,表示已经进行过后置处理
mbd.postProcessed = true;
}
}
.........
Object exposedObject = bean;
try {
//属性赋值阶段
populateBean(beanName, mbd, instanceWrapper);
//初始化Bean阶段
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
........
}
看下applyMergedBeanDefinitionPostProcessors
中的具体内容:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
//会遍历所有注册的 合并Bean定义后置处理器,通过调用postProcessMergedBeanDefinition方法对合并后的Bean定义进行进一步的处理。
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
有6个合并Bean定义的后置处理器:
这6个实现的大致实现逻辑:
AutowiredAnnotationBeanPostProcessor
:这个后置处理器实现了postProcessMergedBeanDefinition
方法,用于处理自动装配注解(如@Autowired
、@Value
等)。它会检查Bean定义中是否使用了这些注解,并根据注解的信息进行自动装配或属性值注入的bean定义缓存处理。RequiredAnnotationBeanPostProcessor
:这个后置处理器实现了postProcessMergedBeanDefinition
方法,用于处理@Required
注解。但它的postProcessMergedBeanDefinition
方法体是空的。它会检查Bean定义中是否使用了@Required
注解,并确保被注解的属性在容器创建Bean时必须被设置。ApplicationListenerDetector
:是用于检测和处理实现了ApplicationListener
接口的Bean。在它所实现的postProcessMergedBeanDefinition
方法中,会对传入的RootBeanDefinition
进行判断,如果该Bean定义的Bean类实现了ApplicationListener
接口,那么就会将该Bean定义标记为一个ApplicationListener
,并将其注册到ApplicationListenerRegistry
中。以便在Spring应用上下文启动后自动触发事件监听。InitDestroyAnnotationBeanPostProcessor
:用于查找Bean定义中关于初始化和销毁的相关处理信息,比如注解@PostConstruct
和@PreDestroy
。缓存到合并Bena定义中用于后续处理。CommonAnnotationBeanPostProcessor
:这个后置处理器实现了postProcessMergedBeanDefinition
方法,用于处理通用注解(如@Resource
、@PostConstruct
、@PreDestroy
等,能处理初始化及销毁主机,是因为它继承了上面那个InitDestroyAnnotationBeanPostProcessor
)。它会检查Bean定义中是否使用了这些注解,并根据注解的信息进行依赖注入或生命周期回调方法的bean定义缓存处理。ScheduledAnnotationBeanPostProcessor
:处理带有@Scheduled
注解的方法,但它的postProcessMergedBeanDefinition
方法体是空的。@Scheduled`注解标记的方法会被注册为定时任务,以便在预定的时间触发执行。这样可以方便地使用注解方式来实现定时任务的调度和执行。
4.getEarlyBeanReference
SmartInstantiationAwareBeanPostProcessor
的getEarlyBeanReference
方法
说白了,SmartInstantiationAwareBeanPostProcessor
的getEarlyBeanReference
方法其实就是用来获取一个早期的、还没有进行属性赋值和初始化的bean,缓存起来用于解决循环依赖的问题。
保证在循环依赖的情况下,每个Bean都能够得到一个有效的引用,从而避免了循环依赖导致的Bean无法获取的问题。
源码调用位置
AbstractAutowireCapableBeanFactory
的doCreateBean
方法中,在修改合并bean定义之后(也是实例化之后),属性赋值阶段之前。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化阶段
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
.........
//通过后置处理器修改合并后的bean定义。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//此处调用了postProcessMergedBeanDefinition方法
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
.........
}
}
/**
* 通过判断当前的Bean定义(mbd):
* 是否是单例----isSingleton(),
* 是否允许循环引用----allowCircularReferences,
* 以及该单例Bean是否当前正在创建中----isSingletonCurrentlyInCreation(beanName)
* 来确定是否进行早期单例对象的暴露----earlySingletonExposure。
* */
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
//如果日志级别为TRACE,会打印一条日志信息,表示正在将Bean名称为beanName的Bean对象缓存起来,以便解决潜在的循环引用问题
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//将一个SingletonFactory对象添加到单例对象工厂中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
//属性赋值阶段
populateBean(beanName, mbd, instanceWrapper);
//初始化Bean阶段
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
........
}
上面的getEarlyBeanReference方法体如下,实际是套了一层来调用SmartInstantiationAwareBeanPostProcessor
的getEarlyBeanReference
方法:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
/**
* 判断是不是合成bean,以及是否有BeanPostProcessor的实现
* isSynthetic():用来判断Bean定义是否为合成Bean的。
* 1.合成Bean是指一种通过编程方式在Spring容器中创建的bean,是在运行时由容器生成的Bean(返回true),往往不会触发完整的生命周期回调和后置处理器的执行
* 2.非合成Bean是指通过XML配置、Java配置(如@Configuration类)或组件扫描等方式创建和定义的bean。会触发所有的生命周期回调和后置处理器的执行
* */
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//如果不是合成bean,并且存在bean后置处理器,则遍历getEarlyBeanReference的实现并调用
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
getEarlyBeanReference
主要有两个实现,AbstractAutoProxyCreator
与MockitoPostProcessor
:
AbstractAutoProxyCreator
是Spring框架提供的一个BeanPostProcessor
实现,用于自动创建代理对象。当应用程序中有配置了需要进行自动代理的Bean时,AbstractAutoProxyCreator
会在Bean创建阶段介入,创建代理对象,然后将代理对象返回作为早期Bean引用。MockitoPostProcessor
是Mockito框架提供的一个BeanPostProcessor
实现,用于在测试中使用Mockito来创建模拟对象。当应用程序中有配置了需要进行Mockito处理的Bean时,MockitoPostProcessor
会在Bean创建阶段介入,使用Mockito框架来创建模拟对象,然后将模拟对象返回作为早期Bean引用。
所以,MockitoPostProcessor
只是用做测试使用,大部分情况下AbstractAutoProxyCreator
是真正运行所需要的。
来看下
AbstractAutoProxyCreator
的getEarlyBeanReference
具体实现
public Object getEarlyBeanReference(Object bean, String beanName) {
//根据bean的类型与名字,生成一个缓存键key
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
//使用缓存键作为key,bean本身作为value存入早期暴露缓存
this.earlyProxyReferences.put(cacheKey, bean);
/**
* 对bean对象进行包装,如果需要代理的话,就生成代理对象并返回;不需要代理就返回包装后的原始对象。
*/
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
Bean属性赋值阶段:
代码总览
在AbstractAutowireCapableBeanFactory 的 doCreateBean
方法中的populateBean
中:
/**
* BeanWrapper 是对Spring Bean进行封装打包的类。
* 在Spring需要反射获取(设置)Bean的字段或者方法时(比如@Autowired注入字段 时),就可以直接通过BeanWrapper获取
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//如果没有BeanWrapper包装类,就不进行bean的属性赋值了
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
//跳过null实例的属性填充阶段
return;
}
}
/*################################此处是`postProcessAfterInstantiation`的调用###############################**/
// 判断当前Bean定义是否为合成bean,并且是否存在bean后置处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//如果存在后置处理器且不是合成bean,则遍历所有的实例化前的后置处理器
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
//判断是否对该Bean进行属性赋值操作
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
/**********************************以下是根据属性的name或type,查找需要注入的属性值*****************************/
//获取bean定义中中是否有需要填充的属性值,没有就返回null
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
//获取自动装配模式,是byType还是byName
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
//判断是否为 `AUTOWIRE_BY_NAME` 或 `AUTOWIRE_BY_TYPE`
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
//将需要注入的属性值添加到集合中-byName的
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
//将需要注入的属性值添加到集合中-byType的
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
//将newPvs赋值给pvs,以确保后续使用。
pvs = newPvs;
}
/**###########################此处是`postProcessProperties`属性赋值修改############################*/
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
//这里调用了postProcessProperties方法
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
/*******************************************注入属性值**************************************/
...............
//这里完成了属性注入,真正将给定的属性值应用到指定的 bean 中
//通过解析引用、深拷贝属性值、处理属性依赖关系和执行属性编辑器转换等操作,确保属性值正确地设置到 bean 的相应属性中。
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
Bean属性赋值之前
5.postProcessAfterInstantiation
InstantiationAwareBeanPostProcessor
的postProcessAfterInstantiation
方法
在实例化之后,属性赋值之前:
postProcessAfterInstantiation
方法作用:对属性赋值操作的扩展,或是自定义实现属性赋值
源码位置
在AbstractAutowireCapableBeanFactory 的 doCreateBean
方法中的populateBean
中:
/**
* BeanWrapper 是对Spring Bean进行封装打包的类。
* 在Spring需要反射获取(设置)Bean的字段或者方法时(比如@Autowired注入字段 时),就可以直接通过BeanWrapper获取
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//如果没有BeanWrapper包装类,就不进行bean的属性赋值了
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
//跳过null实例的属性填充阶段
return;
}
}
/***********************************此处则是`postProcessAfterInstantiation`的调用*****************************/
// 判断当前Bean定义是否为合成bean,并且是否存在bean后置处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//如果存在后置处理器且不是合成bean,则遍历所有的instantiationAware后置处理器
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
//判断是否对该Bean进行属性赋值操作
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
//这里return就结束 populateBean 方法了
return;
}
}
}
/*************以下是根据属性的name或type,查找需要注入的属性值*******************/
//获取bean定义中中是否有需要填充的属性值,没有就返回null
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
//获取自动装配模式,是byType还是byName
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
//判断是否为 `AUTOWIRE_BY_NAME` 或 `AUTOWIRE_BY_TYPE`
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
//将需要注入的属性值添加到集合中-byName的
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
//将需要注入的属性值添加到集合中-byType的
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
//将newPvs赋值给pvs,以确保后续使用。
pvs = newPvs;
}
....................
....................
//属性赋值
applyPropertyValues(beanName, mbd, bw, pvs);
}
然后看下
InstantiationAwareBeanPostProcessor
的postProcessAfterInstantiation
方法实现
进入了CommonAnnotationBeanPostProcessor
这个类
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
写死了直接返回true
,再结合上面代码populateBean
方法的调用:
// 判断当前Bean定义是否为合成bean,并且是否存在bean后置处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//如果存在后置处理器且不是合成bean,则遍历所有的实例化前的后置处理器
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
//判断是否对该Bean进行属性赋值操作
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
//return结束populateBean方法
return;
}
}
}
推断得知,
-
如果当前bean是非合成bean,并且有
InstantiationAwareBeanPostProcessors
的相关实现,就直接return结束方法,不再执行后续的属性赋值了(populateBean
方法中不执行,而是由InstantiationAwareBeanPostProcessors
的实现去执行),直接跳过赋值阶段去初始化bean。 -
而如果是spring容器自己内部生成的bean,就不会return结束,而是继续执行后面的属性注入,然后在初始化bean。
6.postProcessProperties
InstantiationAwareBeanPostProcessor
的postProcessProperties
方法
作用:在Bean属性赋值之前,对Bean的属性值进行进一步的定制和修改。
通常在postProcessProperties
方法中,可以执行以下操作:
- 根据属性值的特定条件进行修改,例如根据某些配置或环境变量的值改变属性的值。
- 添加额外的属性值,例如根据其他属性值计算得出的动态属性。
- 删除或过滤掉不需要的属性值,以控制哪些属性需要注入。
源码位置
在AbstractAutowireCapableBeanFactory 的 doCreateBean
方法中的populateBean
中:
在#号注释下面:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//省略
....................
//此处是`postProcessAfterInstantiation`的调用
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
..........
//此处是查找属性值
autowireByName(beanName, mbd, bw, newPvs);
autowireByType(beanName, mbd, bw, newPvs);
..........
/**###########################此处就是`postProcessProperties`属性赋值前修改####################################*/
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
//这里调用了postProcessProperties方法
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
//省略
...............
//这里完成了属性注入,真正将给定的属性值应用到指定的 bean 中
//通过解析引用、深拷贝属性值、处理属性依赖关系和执行属性编辑器转换等操作,确保属性值正确地设置到 bean 的相应属性中。
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
InstantiationAwareBeanPostProcessor
的postProcessProperties
方法有6个实现
1.AbstractAutoProxyCreator的实现:
不对属性进行任何处理,直接返回原始的PropertyValues
对象
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
return pvs;
}
2.AutowiredAnnotationBeanPostProcessor的实现
该方法的作用是根据自动装配的规则,将合适的属性与相应的Bean进行关联,实现属性的依赖注入。对应@Autowired
如果依赖注入过程中发生异常,会抛出BeanCreationException
异常。
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//根据Bean的名称、类和属性值来查找适用于自动装配的元数据。
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//找到的适用于自动装配的元数据应用到Bean实例上。该方法会使用pvs中的属性值进行依赖注入,将符合自动装配规则的属性与相应的Bean进行关联
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
//返回原始的属性值对象pvs
return pvs;
}
3.CommonAnnotationBeanPostProcessor的实现
该方法的作用是根据使用了@Resource
注解的属性,将其与相应的资源进行关联,实现属性的依赖注入。如果依赖注入过程中发生异常,会抛出BeanCreationException
异常
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//根据Bean的名称、类和属性值来查找使用了@Resource注解的属性的元数据。
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//将找到的适用于依赖注入的元数据应用到Bean实例上。该方法会使用pvs中的属性值进行依赖注入,将使用了@Resource注解的属性与相应的资源进行关联。
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
//返回原始的属性值对象pvs
return pvs;
}
4.ConfigurationClassPostProcessor 的静态内部类 ImportAwareBeanPostProcessor 的实现
@Override
public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
//检查bean是否是EnhancedConfiguration的实例。如果是,说明该Bean是一个增强的配置类
if (bean instanceof EnhancedConfiguration) {
//设置该bean所属的BeanFactory。
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
关于EnhancedConfiguration
:
在Spring中,`EnhancedConfiguration`通常是指使用了`@Configuration`注解的配置类,并且该配置类实现了某个自定义接口或扩展了某个Spring提供的配置类。这样的`EnhancedConfiguration`类可能会添加额外的功能,例如重写某些方法、增加自定义的逻辑或提供特殊的实例化方式等。
在`postProcessProperties`方法中将BeanFactory注入到`EnhancedConfiguration`,是为了确保在自动装配其他配置类之前,`EnhancedConfiguration`已经具备正确的BeanFactory上下文。
为什么需要这样做呢?因为配置类通常会被其他Bean所依赖,并通过自动装配的方式来获取这些依赖。而在进行自动装配之前,需要保证`EnhancedConfiguration`已经获得了正确的BeanFactory上下文,以确保正确解析和处理其他配置类的依赖关系。
一般来讲,实际开发中使用@Configuration
的配置类都是开发者自己去实现或配置了一些spring中的特有功能,来为项目服务。而配置类中的配置可能会被其他bean
所依赖,配置EnhancedConfiguration
的BeanFactory
正是为了该@Configuration
配置类与其他配置类的依赖关系能够正确的被解析与处理。
5.MockitoPostProcessor的实现
MockitoPostProcessor
是用于测试中处理模拟对象的,在实际项目上线运行后是不需要的。
以下代码的意思:通过遍历Bean对象的字段,并调用回调函数对每个字段进行处理,可以实现对字段的定制化操作。
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
//通过ReflectionUtils.doWithFields方法遍历bean对象的所有字段,并调用回调函数对每个字段进行处理,以实现对字段的定制化操作
ReflectionUtils.doWithFields(bean.getClass(), (field) -> {
this.postProcessField(bean, field);
});
return pvs;
}
6.ScriptFactoryPostProcessor的实现
可以将ScriptFactoryPostProcessor
看作是一个空的后置处理器,它不对属性进行任何自定义操作。该方法通常用于实现一些自定义的逻辑。可用于集成groovy脚本加载bean。
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
return pvs;
}
开始Bean属性赋值
执行applyPropertyValues
方法,真正将给定的属性值应用到指定的 bean 中
代码位置
AbstractAutowireCapableBeanFactory 类中的populateBean
方法:
/**
* BeanWrapper 是对Spring Bean进行封装打包的类。
* 在Spring需要反射获取(设置)Bean的字段或者方法时(比如@Autowired注入字段 时),就可以直接通过BeanWrapper获取
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
...............
//`postProcessAfterInstantiation`
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
...............
//根据属性的name或type,查找需要注入的属性值
autowireByName(beanName, mbd, bw, newPvs);
autowireByType(beanName, mbd, bw, newPvs);
//postProcessProperties属性赋值前修改
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
/************************************************属性注入****************************************************/
//这里完成了属性注入,真正将给定的属性值应用到指定的 bean 中
//通过解析引用、深拷贝属性值、处理属性依赖关系和执行属性编辑器转换等操作,确保属性值正确地设置到 bean 的相应属性中。
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
具体来说,applyPropertyValues
方法的作用有以下几点:
- 解析属性值中的运行时引用:对于属性值中的其他 bean 引用,会在该方法中进行解析,确保将正确的 bean 引用赋值给属性。
- 执行属性值的深拷贝:为了避免对原始属性值进行永久性修改,
applyPropertyValues
方法会对属性值进行深拷贝操作。这样,即使在后续的操作中对属性值进行修改,原始属性值也不会受到影响。 - 应用属性值到 bean 对象:将解析后的属性值应用到指定的 bean 对象中,通过
BeanWrapper
对象(bw)将属性值设置到 bean 的相应属性上。 - 处理属性依赖关系:如果在属性值中存在对其他 bean 的依赖关系,会在应用属性值之前处理这些依赖关系,确保所依赖的 bean 先于当前 bean 实例化和初始化。
- 执行属性编辑器转换:如果配置了属性编辑器(PropertyEditor),会在应用属性值之前对属性进行编辑器转换。这可以将字符串类型的属性值转换为目标属性类型所需的类型。
需要注意的是,applyPropertyValues
方法是 AbstractAutowireCapableBeanFactory
的内部方法,在初始化 bean 时会被调用。它通过解析属性值的引用、深拷贝属性值、应用属性值到 bean 对象、处理属性依赖关系以及执行属性编辑器转换等操作,确保属性值正确地被设置到相应的 bean 属性中。
总结起来,applyPropertyValues
方法的主要作用是将给定的属性值应用到指定的 bean 中,通过解析引用、深拷贝属性值、处理属性依赖关系和执行属性编辑器转换等操作,确保属性值正确地设置到 bean 的相应属性中。
Bean初始化阶段:
Bean初始化之前
7.invokeAwareMethods
作用:
invokeAwareMethods
方法用于处理Bean的Aware接口,根据Bean实现的具体Aware接口类型,将相应的资源或信息注入到Bean中。这样,Bean在后续的使用中可以方便地获取自己的名称、ClassLoader或BeanFactory等关键信息。
源码位置
位于初始化Bean的initializeBean
方法中,在AbstractAutowireCapableBeanFactory
的doCreateBean
方法中调用
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//如果应用了java的安全管理器
if (System.getSecurityManager() != null) {
//AccessController.doPrivileged()方法可以在安全管理器的控制下执行特权操作。
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
//调用
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
//没用安全管理器直接调用
else {
//调用
invokeAwareMethods(beanName, bean);
}
//省略
....
....
}
invokeAwareMethods
解析
判断bean是否实现了Aware接口,如果实现了,在判断是否又实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware,如果也实现了,就获取对应的bean名字、bean的类加载器、以及bean工厂,set到bean中用于后续使用。
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
8.postProcessBeforeInitialization
8.1 概念原理
BeanPostProcessor
的postProcessBeforeInitialization
方法
它的作用是在Bean初始化之前对Bean进行扩展操作,可由开发者自定义实现。 spring中也有自带的实现,在我们使用了相应的配置后进行初始化前调用,具体可以参考下方的具体实现。
postProcessBeforeInitialization
方法的大致做如下功能:
- 对Bean进行属性设置或修改:可以在该方法中对Bean的属性进行设置或修改。开发者可以根据需要,动态地修改Bean中的属性值,或者对属性进行一些额外的处理。
- 执行自定义的初始化逻辑:可以在该方法中执行一些自定义的初始化操作。例如,对Bean进行一些额外的初始化逻辑、资源的初始化、打开数据库连接等。
- 返回修改后的Bean对象:可以返回一个修改后的Bean对象,用于替换原始的Bean对象。通过返回修改后的Bean对象,可以对Bean进行增强、代理或其他自定义的操作。
需要注意的是,postProcessBeforeInitialization
方法的返回值类型必须是Object
,它代表经过处理后的Bean对象。如果返回null
,则表示不对Bean对象进行修改,使用原始的Bean对象。
源码
位置:在AbstractAutowireCapableBeanFactory
类的initializeBean
方法。
如果bean定义是空,或者bean定义是是我们自定义配置出来的,就执行初始化之前的后置处理器操作
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//省略
....
invokeAwareMethods(beanName, bean);
/**************************************************************************************/
Object wrappedBean = bean;
//如果bean定义是空,或者bean定义是是我们自定义配置出来的
if (mbd == null || !mbd.isSynthetic()) {
//调用postProcessBeforeInitialization,做初始化之前的后置处理器操作
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
/**************************************************************************************/
//省略
....
....
}
applyBeanPostProcessorsBeforeInitialization
的具体内容:
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
//existingBean是在Bean实例化和属性注入后的初始状态bean。
Object result = existingBean;
//循环遍历所有注册的BeanPostProcessor实例,并依次调用它们的postProcessBeforeInitialization方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
//如果current为null,则说明当前的BeanPostProcessor可能已经修改了Bean对象,则直接返回不再处理
if (current == null) {
return result;
}
result = current;
}
return result;
}
8.2 具体实现
源码中
BeanPostProcessor
的postProcessBeforeInitialization
方法有如下实现类
下面只介绍有具体实现的类,没有介绍的都是如下这种没有具体逻辑的,就不说了:
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
ApplicationContextAwareProcessor
ApplicationContextAwareProcessor
在这个实现类中,主要是调用了一个invokeAwareInterfaces方法,大都是上下文配置相关的东西,通过判断bean的类型来注入相关的配置,用来做以下事情:
- 获取和操作application配置文件中的配置。
- 解析和处理字符串中的占位符或表达式。
- 加载和访问外部资源文件。
- 发布应用程序事件。
- i18n国际化资源处理。
- 获取应用程序的启动信息。
- 获取Spring上下文已经实例化的Bean对象。
代码如下:
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
//将Environment对象注入到Bean中,以获取和操作application配置文件中的配置,或一些系统变量。
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
//将StringValueResolver对象注入到Bean中,以解析和处理字符串中的占位符或表达式
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
//将ResourceLoader对象注入到Bean中,以加载和访问资源文件。
//ResourceLoader为我们提供了一个统一的getResource()方法来通过资源路径检索外部资源。从而将资源或文件(例如文本文件、XML文件、属性文件或图像文件)加载到Spring应用程序上下文中
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
//将ApplicationEventPublisher对象注入到Bean中,用以发布应用程序事件
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
//将MessageSource对象注入到Bean中,用于i18n国际化资源处理
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationStartupAware) {
//ApplicationStartup对象注入到Bean中,以获取应用程序的启动信息
((ApplicationStartupAware)
bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
//将ApplicationContext对象注入到Bean中,主要用来获取Spring上下文已经实例化的Bean对象
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
BeanValidationPostProcessor
BeanValidationPostProcessor
afterInitialization
:判断是否开启了在bean初始化之后进行验证的标志位
通过判断afterInitialization字段的值,来确定是否在Bean的初始化之后执行验证操作。
如果afterInitialization的值为false,代表bean初始化之后不进行验证,那么就要在此处初始化前进行验证。则调用doValidate(bean)
方法进行验证操作
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//通过afterInitialization字段的值,来确定是否在Bean的初始化之后执行验证操作
if (!this.afterInitialization) {
//如果afterInitialization的值为false,则进行验证操作
doValidate(bean);
}
return bean;
}
使用BeanValidationPostProcessor
可以实现以下类型的验证:
- 属性约束验证:通过在Bean属性上添加注解,如
@NotNull
、@Size
、@Min
、@Max
等,来定义属性的约束条件,并在BeanValidationPostProcessor
中进行验证。 - 组验证:通过在Bean上定义验证组,可以根据不同的场景或条件进行属性验证。通过使用
@GroupSequence
注解,可以指定验证组的顺序。 - 自定义验证:使用自定义的验证注解和验证器,可以实现特定的验证逻辑。通过编写自定义的验证注解和对应的验证器,在
BeanValidationPostProcessor
中进行自定义验证。 - 嵌套属性验证:在包含关系的对象中,可以对嵌套属性进行验证。通过在嵌套属性上添加验证注解,可以对其进行验证,并在
BeanValidationPostProcessor
中进行嵌套属性的验证。
BootstrapContextAwareProcessor
BootstrapContextAwareProcessor
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//如果引导上下文bootstrapContext不为null,且bean实现了BootstrapContextAware接口,则调用setBootstrapContext(this.bootstrapContext)方法将引导上下文注入到bean中。
if (this.bootstrapContext != null && bean instanceof BootstrapContextAware) {
((BootstrapContextAware)bean).setBootstrapContext(this.bootstrapContext);
}
return bean;
}
主要是在Bean的初始化之前,通过BootstrapContextAwareProcessor
类将引导Spring应用程序的上下文注入到实现了BootstrapContextAware
接口的Bean中。
我们知道ApplicationContext
是在项目启动过程中完成初始化、注册bean等一系列操作的,但BootstrapContext
是在项目启动前就完成了。
通过设置引导上下文,可以使Bean能够访问和使用引导上下文中的一些特定功能和服务。这样,实现了BootstrapContextAware
接口的Bean在初始化后就可以使用引导上下文所提供的功能。
**引导Spring应用程序的上下文BootstrapContext
**提供了以下主要功能和用途:
- 应用程序上下文的配置加载:
BootstrapContext
负责加载应用程序的配置,例如从属性文件、YAML文件或数据库中加载配置信息。 - BeanFactory的初始化:
BootstrapContext
用于创建和初始化BeanFactory,它是Spring应用程序上下文的核心组件之一。 - 环境的准备:
BootstrapContext
可以准备应用程序运行所需的环境,例如设置系统属性、加载外部资源等。 - 生命周期管理:
BootstrapContext
负责应用程序上下文的生命周期管理,包括创建、刷新、关闭等操作。 - 还可以定义项目启动前需要处理的方法
总的来说,BootstrapContext
是用于引导Spring应用程序的上下文,它提供了一些与引导和初始化相关的功能和服务。通过使用BootstrapContext
,可以实现对引导阶段的配置、资源、环境和配置的管理和访问,以确保Spring应用程序在引导过程中能够正确、高效地进行。
什么是引导阶段:
在Spring中,引导阶段是指在应用程序启动之前的阶段。它是整个Spring框架的初始化和准备阶段,用于完成一些必要的配置和准备工作,以确保应用程序能够正确地运行。
在引导阶段,Spring框架会执行以下主要任务:
加载配置文件:Spring会加载应用程序的配置文件,如XML配置文件或注解配置类。这些配置文件包含了定义Bean、配置依赖关系、设置属性等的信息。
创建并配置Bean工厂:Spring会创建一个Bean工厂,用于管理和创建应用程序中的所有Bean。它会根据配置文件中的定义,实例化Bean对象,并进行依赖注入和属性设置等操作。
扫描和注册组件:Spring会扫描应用程序的类路径,寻找带有特定注解(如@Component、@Service、@Repository等)的类,并将其注册为Spring的组件。这样可以将这些类实例化为Bean并进行管理。
处理Bean的生命周期:Spring会为每个Bean处理生命周期的各个阶段,如实例化、初始化、销毁等。它会调用Bean的初始化方法、销毁方法,并在需要时进行后置处理。
处理AOP相关的配置:如果应用程序使用了AOP(面向切面编程),Spring会处理AOP相关的配置,如切入点表达式、切面定义等。它会为Bean创建代理对象,并将切面逻辑织入到Bean的方法中。
总体来说,引导阶段是指在应用程序启动之前,Spring框架进行初始化和准备的阶段。在这个阶段,Spring会加载配置文件,创建Bean工厂,扫描和注册组件,处理Bean的生命周期,并处理AOP相关的配置。通过这些任务的执行,Spring为应用程序提供了一个可用的运行环境和基础设施,为后续的应用程序逻辑提供支持。
ConfigurationPropertiesBindingPostProcessor
ConfigurationPropertiesBindingPostProcessor
用来处理@ConfigurationProperties
注解,将被@ConfigurationProperties
注解标记的Bean的属性,与配置文件中的对应属性进行绑定,实现属性值的自动注入和配置的管理。
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
this.bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
return bean;
}
@ConfigurationProperties
注解用法简单回顾:
@Component
// 表示把配置文件中前缀为user1的属性的值,赋予到User这个bean中。
@ConfigurationProperties(prefix = "user1")
public class User {
//name的值,对应配置文件中的user1.name
private String name;
// 省略getter/setter方法
}
ErrorPageRegistrarBeanPostProcessor
ErrorPageRegistrarBeanPostProcessor
在Bean的初始化之前,通过ErrorPageRegistrarBeanPostProcessor
类判断Bean是否是ErrorPageRegistry
的实例,如果是,则调用相应的处理方法对其进行处理。
通过这样的处理,可以对实现了ErrorPageRegistry
接口的Bean进行特定的处理,可能包括注册和配置Web应用程序的错误页面。
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ErrorPageRegistry) {
this.postProcessBeforeInitialization((ErrorPageRegistry)bean);
}
return bean;
}
Spring Boot 为我们提供了统一异常处理方式。通过实现ErrorPageRegistrar
接口来注册异常错误提示页面。
示例:
当Controller访问出现404、500、或空指针异常,就返回下面配置的错误页面,页面资源在项目路径下静态资源static文件夹中
@Component
public class CommonErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
// HttpStatus.NOT_FOUND 对应的响应码是404
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/static/errorpage/404.html");
// HttpStatus.INTERNAL_SERVER_ERROR 对应的响应码是500
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/static/errorpage/500.html");
// 根据ErrorPage 的构造函数不仅可以传入Http 对应状态码的枚举,还可以传入对应异常的class 对象
// ErrorPage nullPointException = new ErrorPage(NullPointerException.class, "/对应的提示页面");
registry.addErrorPages(errorPage404, errorPage500);
}
}
ConfigurationClassPostProcessor
ConfigurationClassPostProcessor
在应用中,有时没有把某个类注入到IOC容器中,但在运用的时候需要获取该类对应的bean,此时就需要用到@Import
注解。
而此处正是对应@Import
注解的处理,如果bean使用了@Import(Demo.class)
注解,导入了Demo.class这个类,那么在初始化之前就会利用postProcessBeforeInitialization
方法将Demo.class作为bean注入容器中,并给当前bean使用,或结合当前bean组合实现特定功能。
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
//如果bean是ImportAware示例,就获取相关导入信息并配置到容器中
if (bean instanceof ImportAware) {
ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
if (importingClass != null) {
((ImportAware) bean).setImportMetadata(importingClass);
}
}
return bean;
}
InitDestroyAnnotationBeanPostProcessor
InitDestroyAnnotationBeanPostProcessor
用于Bean的初始化过程中,执行标注了初始化方法注解(如@PostConstruct
)的方法,实现Bean的自定义初始化逻辑。
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//根据Bean的类信息查找与之对应的生命周期元数据
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
//生命周期元数据执行在Bean中标注了初始化方法注解(如@PostConstruct)的方法。
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
LoadTimeWeaverAwareProcessor
LoadTimeWeaverAwareProcessor
这样可以将LoadTimeWeaver
类加载期织入(通过特殊的类加载器,在类字节码加载到JVM时,织入切面)的能力传递给Bean,以支持更高级的类加载和动态代理功能。
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//判断是不是LoadTimeWeaverAware实例
if (bean instanceof LoadTimeWeaverAware) {
//是的话就获取
LoadTimeWeaver ltw = this.loadTimeWeaver;
//如果loadTimeWeaver为null,则通过beanFactory获取LoadTimeWeaver实例
if (ltw == null) {
Assert.state(this.beanFactory != null,
"BeanFactory required if no LoadTimeWeaver explicitly specified");
ltw = this.beanFactory.getBean(
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class);
}
//设置LoadTimeWeaver
((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw);
}
return bean;
}
PropertyMappingContextCustomizer
PropertyMappingContextCustomizer
作用:如果在同一个Bean类上同时存在@PropertyMapping
与@Component
这两个注解,就会抛出异常
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> beanClass = bean.getClass();
MergedAnnotations annotations = MergedAnnotations.from(beanClass, SearchStrategy.SUPERCLASS);
Set<Class<?>> components = annotations.stream(Component.class).map(this::getRoot)
.collect(Collectors.toSet());
Set<Class<?>> propertyMappings = annotations.stream(PropertyMapping.class).map(this::getRoot)
.collect(Collectors.toSet());
if (!components.isEmpty() && !propertyMappings.isEmpty()) {
throw new IllegalStateException("The @PropertyMapping " + getAnnotationsDescription(propertyMappings)
+ " cannot be used in combination with the @Component "
+ getAnnotationsDescription(components));
}
return bean;
}
这段代码的作用是在Bean初始化之前检查@Component
注解和@PropertyMapping
注解的组合使用情况。它通过反射获取bean
的类对象,然后查找和处理标注了这两个注解的注解元素。如果在同一个Bean类上同时存在这两个注解,就会抛出异常,提示不能同时使用这两个注解。这样可以确保在使用@PropertyMapping
注解时,不会与@Component
注解产生冲突。
ServletContextAwareProcessor
ServletContextAwareProcessor
如果ServletContext
和ServletConfig
可用,则将它们设置到Bean中
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (this.getServletContext() != null && bean instanceof ServletContextAware) {
((ServletContextAware)bean).setServletContext(this.getServletContext());
}
if (this.getServletConfig() != null && bean instanceof ServletConfigAware) {
((ServletConfigAware)bean).setServletConfig(this.getServletConfig());
}
return bean;
}
在Bean初始化之前,为实现了ServletContextAware
和ServletConfigAware
接口的Bean设置相应的Servlet环境对象。它检查ServletContext
和ServletConfig
是否可用,并将它们设置到相应的Bean中,以便让Bean能够访问和使用Servlet的上下文信息和配置。
ServletContext:Web上下文对象
每个Web项目都对应了一个上下文对象,上下文对象与项目(模块)是一对一的关系。ServletContext做为域对象可以在整个web应用范围内共享数据
示例ServletContext参数:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>username</param-name>
<param-value>wsl</param-value>
</context-param>
<context-param>
<param-name>age</param-name>
<param-value>18</param-value>
</context-param>
</web-app>
ServletConfig:配置信息
通俗一点说,ServletConfig就代表当前Servlet在web.xml中的配置信息。
<servlet>
<servlet-name>MySerlvet</servlet-name>
<servlet-class>controller.MySerlvet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>liuTongxue</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>MySerlvet</servlet-name>
<url-pattern>/MySerlvet</url-pattern>
</servlet-mapping>
WebServerFactoryCustomizerBeanPostProcessor
WebServerFactoryCustomizerBeanPostProcessor
使用当前bean扩展或修改WebServerFactory
(即web服务器)的配置
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//如果是WebServerFactory的实现,则进行对应配置
if (bean instanceof WebServerFactory) {
//调用了下面的方法
this.postProcessBeforeInitialization((WebServerFactory)bean);
}
return bean;
}
上面的调用了下面这个,对传入的WebServerFactory
进行定制操作。通过回调接口的方式,扩展或修改WebServerFactory
的配置,以满足特定的需求。
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class,
this.getCustomizers(),
webServerFactory,
new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
customizer.customize(webServerFactory);
});
}
org.springframework.boot.web.server.WebServerFactory
是Spring Boot中用于配置和创建Web服务器的接口。
在Spring Boot中,可以使用不同的Web服务器作为应用程序的运行时容器,例如Tomcat、Jetty、Undertow等。WebServerFactory
接口定义了配置和创建Web服务器的方法,以实现不同Web服务器的适配和定制。
具体来说,WebServerFactory
接口定义了以下方法:
getWebServer()
: 用于创建并返回一个新的Web服务器实例。setPort(int port)
: 设置Web服务器监听的端口号。setAddress(InetAddress address)
: 设置Web服务器监听的IP地址。setErrorPages(Set<ErrorPage> errorPages)
: 设置自定义的错误页面配置。setSsl(Ssl ssl)
: 设置SSL配置,用于启用HTTPS。addServerCustomizers(ConfigurableWebServerFactory... factory)
: 添加自定义的Web服务器定制器,用于对Web服务器进行更细粒度的配置。
WebServerFactory
接口的具体实现类包括TomcatServletWebServerFactory
、JettyServletWebServerFactory
和UndertowServletWebServerFactory
等,分别对应使用Tomcat、Jetty和Undertow作为Web服务器的配置。
通过使用WebServerFactory
接口及其实现类,可以轻松配置和创建不同的Web服务器,并进行相应的定制,以满足应用程序的需要。
开始Bean初始化
9.afterPropertiesSet
9.1原理
此处正式执行Bean的初始化,通过invokeInitMethods
方法,有spring自带的初始化方法与自定义的初始化方法:
- 自带的初始化方法,根据不同的
Bean
有不同的实现。 - 自定义的初始化方法则由开发者自己实现。
源码
位置:在AbstractAutowireCapableBeanFactory
的initializeBean
中:invokeInitMethods。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//省略
....
invokeAwareMethods(beanName, bean);
....
//做初始化之前的后置处理器操作
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
/*************************************此处进行初始化******************************************/
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
/**************************************************************************************/
//省略
....
....
}
看下invokeInitMethods
中的具体内容,通过代码得知,此处分为二阶段:
- 一是如果
Bean
实现了InitializingBean
接口,就调用afterPropertiesSet
进行初始化,框架的bean大多使用这种方式; - 二是如果
Bean定义
中存在自定义的初始化方法,就再调用自定义的初始化逻辑。
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//判断该Bean是否实现了InitializingBean接口
boolean isInitializingBean = (bean instanceof InitializingBean);
//如果Bean实现了InitializingBean接口,并且Bean定义中没有配置外部管理的afterPropertiesSet方法,则进入条件判断
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
// 如果日志级别允许,则打印调试日志,表示正在调用afterPropertiesSet方法
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
//如果存在安全管理器,则通过特权访问方式调用afterPropertiesSet方法;否则,直接调用afterPropertiesSet方法。
if (System.getSecurityManager() != null) {
try {
//AccessController特权访问
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//没有安全管理器,直接调用afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
}
//如果Bean定义不为null,且Bean的实际类型不是NullBean,则进入条件判断。
if (mbd != null && bean.getClass() != NullBean.class) {
//获取Bean定义中配置的自定义初始化方法的名称
String initMethodName = mbd.getInitMethodName();
//如果自定义初始化方法的名称不为空,并且不是afterPropertiesSet方法(因为上面已经调用过了),且没有外部管理的初始化方法,则进入条件判断。
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
//调用自定义的初始化方法,执行Bean的初始化逻辑。
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
afterPropertiesSet
方法的实现太多,列举部分
1.MybatisSqlSessionFactoryBean
构建并设置了SqlSessionFactory
实例
2.DruidStatInterceptor
将Spring的统计信息和上下文监听器添加到Druid连接池中,以便在连接池的运行过程中进行统计和处理
public class DruidStatInterceptor implements MethodInterceptor, InitializingBean, DisposableBean {
public void afterPropertiesSet() throws Exception {
//将springStat对象添加到SpringStatManager中,
//SpringStatManager是Druid连接池中用于管理Spring相关统计信息的管理器。
//通过添加springStat对象,Druid连接池可以统计Spring方法的执行情况。
SpringStatManager.getInstance().addSpringStat(springStat);
//将statContextListener对象添加到StatFilterContext中作为上下文监听器。
//StatFilterContext是Druid连接池中用于管理过滤器上下文的类。
//通过添加上下文监听器,Druid连接池可以在特定事件发生时通知statContextListener对象,以便进行一些额外的处理。
StatFilterContext.getInstance().addContextListener(this.statContextListener);
}
}
3.ExecutorConfigurationSupport
根据不同的子类实现,创建和配置ExecutorService
线程池的实例
public abstract class ExecutorConfigurationSupport extends CustomizableThreadFactory
implements BeanNameAware, InitializingBean, DisposableBean {
@Nullable
private ExecutorService executor;
@Override
public void afterPropertiesSet() {
initialize();
}
/**
* Set up the ExecutorService.
*/
public void initialize() {
if (logger.isDebugEnabled()) {
logger.debug("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (!this.threadNamePrefixSet && this.beanName != null) {
setThreadNamePrefix(this.beanName + "-");
}
this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
}
}
4.Jackson2ObjectMapperFactoryBean
配置ObjectMapper
。ObjectMapper
是Jackson库中的一个核心类。它是用于JSON序列化和反序列化的主要工具之一,可以进行java对象与json字符串的互转。
public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper>, BeanClassLoaderAware, ApplicationContextAware, InitializingBean {
@Nullable
private ObjectMapper objectMapper;
public void afterPropertiesSet() {
if (this.objectMapper != null) {
//如果objectMapper不为空,则对objectMapper进行进一步的配置
this.builder.configure(this.objectMapper);
} else {
//如果objectMapper不为空,则创建一个objectMapper实例
this.objectMapper = this.builder.build();
}
}
}
9.2自定义初始化方法
一阶段的afterPropertiesSet
方法是由Spring容器在配置Bean时自动调用的。而我们仍然可以进行自定义对初始化做额外的操作:
主要有三种方式:
使用
@PostConstruct
注解
- 在自定义的初始化方法上添加
@PostConstruct
注解。 - 确保Spring容器在实例化Bean并完成属性注入后调用该方法。
- 注意,要使用
javax.annotation.PostConstruct
注解。
@Component
public class MyBean {
@PostConstruct
public void init() {
// 执行自定义初始化逻辑
}
}
使用
init-method
属性
- 在XML配置文件中的
<bean>
标签中,通过init-method
属性指定自定义初始化方法的名称。 - Spring容器在实例化Bean并完成属性注入后,会调用指定的方法进行初始化。
<bean id="myBean" class="com.example.MyBean" init-method="init" />
public class MyBean {
public void init() {
// 执行自定义初始化逻辑
}
}
实现
InitializingBean
接口
- 让Bean类实现
InitializingBean
接口,并实现afterPropertiesSet
方法。 - Spring容器在实例化Bean并完成属性注入后,会自动调用
afterPropertiesSet
方法进行初始化。
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 执行自定义初始化逻辑
}
}
无论使用哪种方式,自定义初始化方法应该用于执行一些与Bean相关的初始化逻辑,例如建立数据库连接、初始化资源、加载配置等。在初始化方法中,可以对Bean的属性进行验证和初始化,处理依赖关系,执行其他初始化逻辑,以确保Bean在使用之前处于正确的状态。
Bean初始化之后
10.postProcessAfterInitialization
10.1原理
BeanPostProcessor
的postProcessAfterInitialization
方法
作用:在目标bean完成初始化后,对其进行额外的处理或修改。
常见的用途包括:
- 对目标bean的属性进行修改或校验:可以在此方法中对目标bean的属性进行一些额外的处理或校验,例如对属性进行初始化、修改或验证。
- 对目标bean进行代理或包装:可以在此方法中对目标bean进行代理,例如通过AOP框架对目标bean应用切面逻辑,或者通过包装器将目标bean包装在其他对象中。
- 对目标bean进行一些其他定制逻辑:可以根据业务需求在此方法中进行一些其他的定制逻辑,例如注册额外的监听器、设置一些属性值等。
需要注意的是,postProcessAfterInitialization
方法并不负责目标bean的实例化和依赖注入,它仅在目标bean的初始化之后进行处理
源码
位置:在AbstractAutowireCapableBeanFactory
的initializeBean
中。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//省略
....
//获取bean信息
invokeAwareMethods(beanName, bean);
....
//调用postProcessBeforeInitialization,做初始化之前的后置处理器操作
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
....
//执行初始化
invokeInitMethods(beanName, wrappedBean, mbd);
/*******************************************************************************************/
//如果bean定义是空,或者不是合成bean,则调用postProcessAfterInitialization做初始化之后的后置处理操作
if (mbd == null || !mbd.isSynthetic()) {
//调用postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
}
看下applyBeanPostProcessorsAfterInitialization
中的具体内容:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
//经过上面的一系列步骤,existingBean是已经初始化的bean对象
Object result = existingBean;
//获取容器中所有注册的Bean后置处理器,进行遍历
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
//如果为null,表示该Bean后置处理器不再返回任何结果,直接返回之前的处理结果result
if (current == null) {
return result;
}
//如果不为空,则将上一次遍历处理的结果放入下一次循环继续叠加处理,直到结束
result = current;
}
return result;
}
10.2 具体实现
源码中
BeanPostProcessor
的postProcessAfterInitialization
方法有如下实现
下面只介绍有具体逻辑实现的类,没有介绍的都是如下这种没有具体实现直接返回的,就不写了:
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
AbstractAdvisingBeanPostProcessor
AbstractAdvisingBeanPostProcessor
的postProcessAfterInitialization
方法
作用:在Bean初始化完成后,对目标Bean进行增强的处理。它可以根据配置的增强规则,为目标Bean添加额外的功能(如切面、拦截器等)。
它执行两个判断:
- 如果当前bean已经是代理bean,则将
advisor
(切点+通知)添加到现有代理bean的advisor
链(List)中; - 如果当前bean不是代理bean,但满足了切面条件,则根据当前bean创建一个新的代理bean,并将
advisor
(切点+通知)添加到代理bean中; - 如果以上条件都不满足,则直接返回原始的bean对象,不进行任何代理。
源码解析
看源码之前先了解几个东西:
-
AopInfrastructureBean
:AopInfrastructureBean是一个标记接口。若Bean实现了此接口,表明它是一个Spring AOP的基础类,那么这个类是不会被AOP给代理的,即使它能被切面切进去。
-
Advised
是不是就是标记@Aspect
注解的类?被@Aspect注解标记的类所生成的代理对象是Advised接口的实现类,该实现类中包含@Aspect配置类中定义的切点、通知等信息。 但并不是所有实现了Advised接口的对象都是由@Aspect注解标记的类所生成的,比如用非注解方式实现的aop也会实现Advised接口。
-
advisor
(切点+通知)可以理解为是
@Aspect
配置类中,配置的切点和通知,即被@Pointcut(*)
标记的切点,@Before
、@After
等所标记的通知方法
源码:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
//如果advisor为空,并是AopInfrastructureBean实现,则直接返回不处理
//若Bean实现了AopInfrastructureBean,则不会被AOP代理
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
return bean;
}
//判断bean是不是代理bean,实现了Advised接口的类都是代理类
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
/* isFrozen():判断是否已被冻结
AopUtils.getTargetClass(bean)获取目标对象的实际类,即去除代理的目标类,或者说是被代理类
isEligible作用是:检查参数中的bean是否满足切面条件(可以理解为,执行这段代码的代理bean的原bean类,是不是@Aspect切面配置中所切入的那个类,当然切面配置类不止可以用@Aspect注解实现)
*/
//总结上面注释,这个if就是判断此代理bean是不是正确的代理了目标bean
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
/*
如果满足条件,则将当前advisor(切点+通知,即@Aspect配置类中的@Pointcut、@Before、@After等)
添加到现有代理advised的切面链中,并返回代理对象
切面链:一个List<advisor>,因为一个@Aspect切面配置类可能切入了多个类
this.beforeExistingAdvisors:这个属性的作用是控制切面的顺序,
beforeExistingAdvisors为true,表示从切面链List<advisor>集合现有元素的前面添加,为false从后面添加
*/
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
//检查当前bean是否满足切面条件
if (isEligible(bean, beanName)) {
//根据当前代理bean创建一个代理工厂
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
//将切点+通知加入到代理工厂
proxyFactory.addAdvisor(this.advisor);
//执行一些自定义的代理工厂设置
customizeProxyFactory(proxyFactory);
//获取代理的类加载器,并根据类加载器创建代理对象
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
//返回代理对象
return proxyFactory.getProxy(classLoader);
}
//如果以上条件都不满足,则直接返回原始的bean对象,不进行任何代理。
return bean;
}
AbstractAutoProxyCreator
AbstractAutoProxyCreator
的postProcessAfterInitialization
方法
作用是判断当前bean是否已经被替换为代理对象,如果是,则创建当前bean的代理bean对象进行包装并返回,否则直接返回原始的bean对象。
此处会对应实例化后所调用的getEarlyBeanReference
方法,也在AbstractAutoProxyCreator
类中。实例化bean后getEarlyBeanReference
方法会在缓存中存放一个早期的原始bean,用于处理循环依赖问题,如果bean需要代理,源码中是在存完缓存后才进行代理的,所以缓存中不会直接存放代理Bean。而是在存放完成后进行代理,替换掉原bean,回顾其代码:
public Object getEarlyBeanReference(Object bean, String beanName) {
//根据bean的类型与名字,生成一个缓存键key
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
//使用缓存键作为key,bean本身作为value存入早期暴露缓存
this.earlyProxyReferences.put(cacheKey, bean);
/**
* 对bean对象进行包装,如果需要代理的话,就生成代理对象并返回;不需要代理就返回包装后的原始对象。
*/
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
此时在看postProcessAfterInitialization
方法,如果bean在实例化后被代理了,那么此处的remove判断,一定不相等,则证明了当前bean是代理bean,这里就需要创建对应的代理bean并返回。
而为什么要移除之前缓存的原始bean,与三级缓存有关,初始化后的bean比原始bean更加完整,所以不需要缓存原始bean了。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//根据bean名与类型从缓存中获取缓存键
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//从earlyProxyReferences集合中移除以cacheKey为键的对象,
//如果移除的对象不等于原始的bean对象,则表示在早期代理引用的过程中,该目标bean已被替换为代理对象。
//要调用wrapIfNecessary(bean, beanName, cacheKey)方法对代理对象进行包装,并返回包装后的代理对象。
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
那么,为什么要调用两次
wrapIfNecessary
方法呢?
getEarlyBeanReference
方法中调用wrapIfNecessary
,是在Bean实例化的早期被调用,是为了确保在Bean实例化后可以立即使用代理对象。但这样可能会存在一些问题。例如,如果Bean对象的某些依赖关系在实例化后的早期阶段还未完全注入,或者相关的Bean后处理器尚未应用,则可能导致代理对象无法正确创建,从而引发错误。
而在postProcessAfterInitialization
方法中再次调用wrapIfNecessary
,是为了确保了依赖注入和其他后处理器的正常执行,从而保证代理对象的正确创建。
AbstractAutoProxyCreator
的postProcessAfterInitialization
方法中,通过wrapIfNecessary
来创建了代理bean,而
AbstractAdvisingBeanPostProcessor
的postProcessAfterInitialization
方法中,也用了相似的逻辑创建了代理bean,那么二者有何不同呢?
它们的主要区别在于使用的场景和功能:
AbstractAdvisingBeanPostProcessor
是一个用于AOP面向切面编程的后处理器。它主要用于在Bean初始化后,对目标Bean应用增强逻辑(如通知、拦截器等)。它的代理是在初始化后才创建的。
AbstractAutoProxyCreator
是一个用于自动代理的后处理器。它主要用于根据一些规则自动为Bean创建代理对象,而无需显式配置。它的代理在bean实例化后就创建了,虽然在初始化后又创建了一遍,但后者是对前者的补充。
AdvisorAdapterRegistrationManager
AdvisorAdapterRegistrationManager
的postProcessAfterInitialization
方法
该方法的作用是在目标bean的初始化之后判断是否为AdvisorAdapter
的实例,并将其注册到适配器注册表中。这样,在AOP代理过程中,当需要将Advisor
适配到目标对象时,可以使用已注册的适配器进行适配。
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof AdvisorAdapter){
this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter) bean);
}
return bean;
}
Advisor
是什么
Advisor
是一个包含切点(Pointcut)和通知(Advice)的对象,它定义了在目标对象的方法执行过程中何时何地应用通知。但是,目标对象和AOP框架之间存在接口和实现的差异,Advisor并不能直接应用到目标对象上。
AdvisorAdapter的作用就是解决这种差异,它充当一个适配器,将Advisor和目标对象之间进行适配。
源码中何处使用了
Advisor
及AdvisorAdapter
AdvisorAdapter有三个实现类:
他们在DefaultAdvisorAdapterRegistry
中被使用:
DefaultAdvisorAdapterRegistry
又是GlobalAdvisorAdapterRegistry
的实例属性:
GlobalAdvisorAdapterRegistry
又在AbstractAutoProxyCreator
中被使用
在AbstractAutoProxyCreator
的createProxy
方法中,创建代理bean时,会调用
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
来将 advisor
切点+通知 添加到代理bean中,用于目标对象在实际被调用时的aop通知执行
关于aop代理的方法拦截器
在DefaultAdvisorAdapterRegistry
中getInterceptors
方法:
方法拦截器是由 advisor
切点+通知 转化而来的,用于切点所标记的被代理目标对象的方法执行时,进行执行拦截,从而执行我们的切面方法。
ApplicationListenerDetector
ApplicationListenerDetector
的postProcessAfterInitialization
方法
作用:将实现了ApplicationListener
监听器接口的Bean添加到AbstractApplicationContext
上下文中
源码:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
//判断bean类型是不是监听器
if (bean instanceof ApplicationListener) {
//判断bean是不是单例
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
//是单例就添加到spring的上下文中
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
//不是单例就输出警告日志
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
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.");
}
//将该bean从singletonNames中移除
this.singletonNames.remove(beanName);
}
}
return bean;
}
- 首先,判断当前的bean是否实现了ApplicationListener接口(即是否是一个事件监听器)。
- 如果是一个事件监听器,进一步判断该bean是否是单例的。
- 如果是单例的,将该bean注册到ApplicationContext中,以便能够接收到相应的事件。
- 如果不是单例的,会有警告日志输出,并将该bean从singletonNames中移除,因为非单例的bean无法可靠地处理事件。
- 最后,将原始的bean返回。
换句话说,这段代码的目的是确保实现了ApplicationListener接口的bean能够被正确地注册为事件监听器,并能够接收到相应的事件。对于非单例的bean,由于无法可靠地处理事件,会产生相应的警告信息,并将其从singletonNames中移除,以免引起不必要的问题。
非单例的事件监听器Bean无法可靠地处理事件,主要是因为以下原因:
1.作用域问题:非单例的Bean可能拥有多个实例,每个实例都有自己的状态和属性。当事件发生时,无法确定应该将事件传递给哪个实例进行处理,因为无法确定哪个实例是当前有效的。
2.生命周期问题:非单例的Bean在容器中的生命周期可能与事件发生的时机不一致。当事件发生时,可能某些非单例的Bean还未被创建或已经被销毁,导致无法正常处理事件。
3.并发问题:非单例的Bean可能同时被多个线程访问和修改。当多个线程同时触发事件时,非单例的Bean可能会出现竞态条件或线程安全问题,导致事件的处理结果不可靠。
因此,为了确保事件的可靠处理,Spring AOP要求事件监听器Bean必须是单例的。只有单例的Bean才能够确保在事件发生时,能够正确处理事件并保持一致的状态和逻辑。
当开发者将一个非单例的Bean实现了ApplicationListener接口时,Spring会发出警告提示,提醒开发者非单例事件监听器的局限性。这样做是为了保证事件的可靠处理,避免潜在的问题和不可预测的结果。
事件监听器
在Spring框架中,事件监听器可以监听到ApplicationContext
发布的各种事件,如上下文初始化完成事件、Bean创建完成事件等。
通过实现ApplicationListener
接口,开发者可以自定义事件监听器,并在事件发生时执行相应的逻辑。这段代码就是用来确保事件监听器的正确注册和处理的。
PostProcessorRegistrationDelegate
在
PostProcessorRegistrationDelegate
的内部类BeanPostProcessorChecker
中的postProcessAfterInitialization
方法
判断当前bean是否符合,被所有Bean后置处理器处理的条件。
源码
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (!(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
if (logger.isInfoEnabled()) {
logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() +
"] is not eligible for getting processed by all BeanPostProcessors " +
"(for example: not eligible for auto-proxying)");
}
}
return bean;
}
-
首先,判断当前的bean是否是BeanPostProcessor的实现类,即判断是否是Bean后置处理器。
-
如果不是Bean后置处理器,并且这个bean不是基础设施bean(Infrastructure Bean)(即不是由Spring容器内部使用的bean),并且当前已经注册的Bean后置处理器数量小于目标数量(beanPostProcessorTargetCount),则执行以下逻辑:
输出日志信息,将该bean的名称、类名以及原因记录下来。日志信息描述了该bean不符合被所有Bean后置处理器处理的条件,比 如不符合自动代理的条件。
-
最后,将原始的bean返回。
该代码的目的是为了记录那些,不符合被所有Bean后置处理器处理的条件的bean。通常情况下,所有的bean都应该被所有的Bean后置处理器处理,但在某些情况下,可能有一些特殊的bean不符合处理条件,这个代码就是用来记录这些情况,以便开发者能够了解到哪些bean无法得到期望的后置处理。
BeanValidationPostProcessor
BeanValidationPostProcessor
的postProcessAfterInitialization
方法
**作用:**在Bean初始化之后,根据配置的验证规则对当前的bean进行验证操作。通过在BeanValidationPostProcessor中添加验证逻辑,可以在Bean初始化之后对其进行自定义的验证操作,以确保bean的合法性和一致性。
源码
afterInitialization
:判断是否开启了在初始化之后进行验证的标志位
通过判断afterInitialization字段的值,来确定是否在Bean的初始化之后执行验证操作。
如果afterInitialization的值为true,则代表需要在初始化之后调用doValidate(bean)
方法进行验证操作
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (this.afterInitialization) {
doValidate(bean);
}
return bean;
}
使用BeanValidationPostProcessor
可以实现以下类型的验证:
- 属性约束验证:通过在Bean属性上添加注解,如
@NotNull
、@Size
、@Min
、@Max
等,来定义属性的约束条件,并在BeanValidationPostProcessor
中进行验证。 - 组验证:通过在Bean上定义验证组,可以根据不同的场景或条件进行属性验证。通过使用
@GroupSequence
注解,可以指定验证组的顺序。 - 自定义验证:使用自定义的验证注解和验证器,可以实现特定的验证逻辑。通过编写自定义的验证注解和对应的验证器,在
BeanValidationPostProcessor
中进行自定义验证。 - 嵌套属性验证:在包含关系的对象中,可以对嵌套属性进行验证。通过在嵌套属性上添加验证注解,可以对其进行验证,并在
BeanValidationPostProcessor
中进行嵌套属性的验证。
BeanValidationPostProcessor
是Spring框架中一个用于支持JSR-303 Bean验证的后置处理器。它可以应用于使用注解进行验证的JavaBean对象上。
以下是一些常用的验证注解,可以用于BeanValidationPostProcessor
进行验证的JavaBean上:
- @NotNull:用于验证对象是否为null。
- @NotEmpty:用于验证字符串、集合或数组是否为空。
- @NotBlank:用于验证字符串是否非空且不包含空格。
- @Size:用于验证字符串、集合或数组的长度是否在指定范围内。
- @Min:用于验证数字是否大于等于指定最小值。
- @Max:用于验证数字是否小于等于指定最大值。
- @Pattern:用于验证字符串是否匹配指定的正则表达式。
- @Email:用于验证字符串是否是有效的电子邮件地址。
- @AssertTrue:用于验证布尔类型的字段或方法是否为true。
- @AssertFalse:用于验证布尔类型的字段或方法是否为false。
除了以上列举的常用验证注解,还有很多其他的验证注解可以使用。这些注解可以通过在JavaBean的字段、getter或者setter方法上进行声明,以指定对应字段的验证规则。然后,在BeanValidationPostProcessor中使用这些注解进行验证,以确保JavaBean对象的数据的有效性和一致性。
JsonTestersAutoConfiguration
JsonTestersAutoConfiguration
类的内部类JsonMarshalTestersBeanPostProcessor
中postProcessAfterInitialization
方法
作用:在Bean初始化之后,对bean中的属性(Field,也是成员变量)进行处理
源码
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), (field) -> processField(bean, field));
return bean;
}
- 首先,使用ReflectionUtils的doWithFields方法,遍历bean的所有字段。
- 对于每个字段,调用processField方法对字段进行处理。
- 最后,将原始的bean返回。
这段代码的目的是在Bean初始化之后,对bean的字段进行特定的处理操作。通过遍历bean的所有字段,并调用processField方法,开发者可以在该方法中实现自定义的逻辑,对字段进行操作,例如修改字段的值或者进行其他处理。这样可以在Bean初始化之后对字段进行额外的操作,以满足特定的需求。
ScheduledAnnotationBeanPostProcessor
ScheduledAnnotationBeanPostProcessor
类中的postProcessAfterInitialization
方法
作用:在Bean初始化之后,通过检查目标类是否存在@Scheduled
注解的方法,如果存在就根据这些方法创建定时任务,以实现定时任务的调度执行
源码
如果bean有@Scheduled
或@Schedules
的派生注解,就用MethodIntrospector.selectMethods
查出标记定时注解的方法,如果能查出来,就创建对应的定时任务,从而实现任务的调度和定时执行
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
//如果bean是if中的这个几个bean的实例,则直接返回
if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||
bean instanceof ScheduledExecutorService) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
//获取bean的真实类,即去掉代理的真实类
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
//目标类不在无注解类集合中,并且目标类是标记为@Scheduled或@Schedules注解的候选类,则进入if
if (!this.nonAnnotatedClasses.contains(targetClass) &&
AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {
//找到目标类中所有标记有@Scheduled或@Schedules注解的方法,并将它们的注解信息存储在annotatedMethods集合中。
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method ->
{
Set<Scheduled> scheduledAnnotations = AnnotatedElementUtils
.getMergedRepeatableAnnotations(
method, Scheduled.class, Schedules.class);
return (!scheduledAnnotations.isEmpty() ? scheduledAnnotations : null
);
}
);
//如果annotatedMethods集合为空,表示该目标类没有带有@Scheduled注解的方法,则将目标类添加到nonAnnotatedClasses集合中,并输出相应的日志信息。
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(targetClass);
if (logger.isTraceEnabled()) {
logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
}
}
//否则,遍历annotatedMethods集合,对每个带有@Scheduled注解的方法执行processScheduled方法进行处理;
//通过processScheduled将根据目标bean中标记定时注解的方法为其创建定时任务
//最后输出相应的日志信息。
else {
// Non-empty set of methods
annotatedMethods.forEach((method, scheduledAnnotations) ->
scheduledAnnotations.forEach(scheduled -> processScheduled(scheduled, method, bean)));
if (logger.isTraceEnabled()) {
logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName +
"': " + annotatedMethods);
}
}
}
return bean;
}
SimpleServletPostProcessor
SimpleServletPostProcessor
类的postProcessAfterInitialization
方法
作用:在Bean初始化之后,对实现了Servlet接口的bean,根据其ServletConfig
,进行初始化操作,
源码
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//判断bean是否是Servlet的实例
if (bean instanceof Servlet) {
//获取Servlet的Config
ServletConfig config = this.servletConfig;
//如果config为空,或者不使用共享config
if (config == null || !this.useSharedServletConfig) {
//根据servlet的上下文创建一个委托的config配置类,用于当前Servlet-bean自己初始化使用
config = new DelegatingServletConfig(beanName, this.servletContext);
}
try {
//根据配置初始化servlet
((Servlet) bean).init(config);
}
catch (ServletException ex) {
throw new BeanInitializationException("Servlet.init threw exception", ex);
}
}
return bean;
}
MockitoPostProcessor
MockitoPostProcessor
的内部类SpyPostProcessor
的postProcessAfterInitialization
方法
作用:在bean初始化之后,处理通过Mockito
创建的代理对象,以实现对bean的模拟和监视。
Mockito
创建的是一个用于模拟和监视真实对象的代理对象,它可以用于测试中的模拟操作和行为验证。只是用于测试!实际运行不需要
源码
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//判断bean是否是FactoryBean的实例。如果是,直接返回。
if (bean instanceof FactoryBean) {
return bean;
}
//将移除的bean与当前bean进行比较
//如果不相等,则表示该bean是通过Mockito创建的代理对象,需要进行处理。
if (this.earlySpyReferences.remove(getCacheKey(bean, beanName)) != bean) {
//创建mockito代理bean,用于测试
return this.mockitoPostProcessor.createSpyIfNecessary(bean, beanName);
}
return bean;
}
后续
registerDisposableBeanIfNecessary
作用:将bean注册为可销毁bean,即在容器关闭后会调用bean的销毁方法。
(具体的关闭及销毁方法调用,参照ConfigurableApplicationContext
的close
方法)
在
AbstractAutowireCapableBeanFactory
的doCreateBean
方法最后
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//省略实例化、初始化
.............
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
进入
registerDisposableBeanIfNecessary
方法中
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
//获取安全管理器的访问控制上下文(AccessControlContext),以便在需要的情况下进行安全控制
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
// 如果 bean 不是原型作用域且需要销毁,根据 bean 的作用域类型进行不同的处理
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
//如果 bean 是单例作用域
if (mbd.isSingleton()) {
//注册一个 DisposableBeanAdapter 对象,负责执行所有与销毁相关的工作,包括 DestructionAwareBeanPostProcessors、DisposableBean 接口和自定义销毁方法。
registerDisposableBean(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
//如果 bean 是非单例作用域、或自定义作用域
else {
//获取bean的作用域
Scope scope = this.scopes.get(mbd.getScope());
//无法获取到bean的作用域,则抛出异常
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
//根据 bean 的作用域类型获取相应的 Scope 对象,并在该 Scope 对象中注册一个 DisposableBeanAdapter 对象,同样负责执行与销毁相关的工作。
scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
}
}
afterSingletonsInstantiated
SmartInitializingSingleton
的afterSingletonsInstantiated
方法
作用:在所有单例 bean 实例化完成后进行一些特定的初始化操作,可自定义
源码
在 DefaultListableBeanFactory 类中 preInstantiateSingletons
方法内的最后面:
@Override
public void preInstantiateSingletons() throws BeansException {
...........
//遍历所有的 bean 名称
for (String beanName : beanNames) {
//获取相应的单例实例
Object singletonInstance = getSingleton(beanName);
//如果单例实例实现了 SmartInitializingSingleton 接口,执行特定的初始化操作。
if (singletonInstance instanceof SmartInitializingSingleton) {
//使用 StartupStep 开始计时,并记录相关的标签信息。
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
//将bean转为SmartInitializingSingleton实例,下面来使用
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
//如果存在安全管理器
if (System.getSecurityManager() != null) {
//使用 AccessController.doPrivileged 方法在安全情况下执行
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
//如果不存在安全管理器,直接执行
else {
smartSingleton.afterSingletonsInstantiated();
}
//结束
smartInitialize.end();
}
}
}
已有实现
CacheAspectSupport
源码解析
@Override
public void afterSingletonsInstantiated() {
//检查当前的缓存解析器是否为空。
if (getCacheResolver() == null) {
//为空就是用断言报错,来确保 `beanFactory` 不为空
Assert.state(this.beanFactory != null, "CacheResolver or BeanFactory must be set on cache aspect");
try {
//尝试通过 `beanFactory` 获取一个 `CacheManager` 实例,作为默认的缓存管理器
setCacheManager(this.beanFactory.getBean(CacheManager.class));
}
//如果存在多个 `CacheManager` 缓存解析器实例,就抛出异常,表示无法确定要使用哪个
catch (NoUniqueBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.", ex);
}
//没有找到也抛异常
catch (NoSuchBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.", ex);
}
}
//将 `initialized` 标志设置为 `true`,表示初始化完成
this.initialized = true;
}
具体来说,代码的逻辑如下:
- 首先,检查当前的缓存解析器(
getCacheResolver()
)是否为空。 - 如果缓存解析器为空,表示缓存管理器尚未初始化,需要进行延迟初始化。
- 确保
beanFactory
不为空(通过断言this.beanFactory != null
)。 - 尝试通过
beanFactory
获取一个CacheManager
实例,作为默认的缓存管理器。 - 如果存在多个
CacheManager
实例,抛出NoUniqueBeanDefinitionException
异常,表示无法确定要使用的CacheManager
。 - 如果没有找到
CacheManager
实例,抛出NoSuchBeanDefinitionException
异常,表示没有找到任何可用的CacheManager
实例。 - 如果成功获取到
CacheManager
实例,将其设置为当前的缓存管理器(setCacheManager()
)。 - 将
initialized
标志设置为true
,表示初始化完成。
总结来说,这段代码的作用是在所有单例 bean 实例化完成后,检查并延迟初始化缓存管理器。通过获取 CacheManager
实例来设置缓存管理器,以确保在使用缓存功能之前,缓存解析器和缓存管理器已经准备就绪。
CacheAspectSupport
类是什么,有什么用?
CacheAspectSupport
类是 Spring 框架中与缓存相关的切面支持类,用于提供缓存功能的支持。
具体来说,CacheAspectSupport
类的主要作用如下:
- 提供了缓存切面的基本实现,作为其他缓存切面的基类。
- 实现了
SmartInitializingSingleton
接口,以确保在所有单例 bean 实例化完成后进行缓存相关的初始化操作。 - 提供了与缓存解析器和缓存管理器相关的属性和方法,用于配置和获取缓存相关的组件。
- 提供了方法用于将缓存注解应用到目标方法上,实现缓存的读取、更新和清除操作。
- 提供了方法用于处理缓存的异常情况,如缓存读写异常、缓存注解配置错误等。
- 通过
CacheOperationSource
接口实现,提供了解析和管理缓存注解的能力。 - 提供了方法用于获取缓存统计信息,如缓存命中率、缓存命中次数等。
总的来说,CacheAspectSupport
类是 Spring 框架中与缓存相关的切面支持类,用于提供缓存功能的基本实现和支持。它封装了缓存切面的核心逻辑,使得开发者可以方便地在 Spring 应用中使用缓存来提高性能和效率。
CacheAspectSupport
类可以与多种缓存使用
在 Spring 框架中,通过实现 org.springframework.cache.CacheManager
接口和相应的缓存适配器,可以集成各种缓存提供商。这些缓存提供商包括 Redis、Ehcache、Caffeine 等。
使用 CacheAspectSupport
类时,可以配置相应的缓存管理器(CacheManager
)和缓存解析器(CacheResolver
),以指定要使用的缓存提供商。这样,在应用程序中使用 @Cacheable
、@CachePut
、@CacheEvict
等缓存注解时,CacheAspectSupport
类会根据配置的缓存管理器和缓存解析器来实现相应的缓存操作。
对于 Redis 缓存,可以使用 Spring 提供的 RedisCacheManager
作为缓存管理器,并配置相应的 Redis 连接工厂(RedisConnectionFactory
)来连接 Redis 数据库。然后,将 RedisCacheManager
设置为 CacheAspectSupport
类的缓存管理器,就可以使用 Redis 作为缓存提供商。
需要注意的是,具体的集成和配置方式可能会因为使用的 Spring 版本和缓存提供商的不同而有所差异。因此,在使用 CacheAspectSupport
类时,需要根据具体的需求和环境进行相应的配置和集成。
CacheProxyFactoryBean
源码解析
@Override
public void afterSingletonsInstantiated() {
this.cacheInterceptor.afterSingletonsInstantiated();
}
进入上面的cacheInterceptor.afterSingletonsInstantiated()
中,发现实际上就是CacheAspectSupport
的afterSingletonsInstantiated
方法,具体含义上面已介绍,此处不在解释。
@Override
public void afterSingletonsInstantiated() {
if (getCacheResolver() == null) {
// Lazily initialize cache resolver via default cache manager...
Assert.state(this.beanFactory != null, "CacheResolver or BeanFactory must be set on cache aspect");
try {
setCacheManager(this.beanFactory.getBean(CacheManager.class));
}
catch (NoUniqueBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.", ex);
}
catch (NoSuchBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.", ex);
}
}
this.initialized = true;
}
CacheInterceptor
CacheProxyFactoryBean
中,是使用了CacheInterceptor
缓存拦截器来调用了CacheAspectSupport
:
public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean
implements BeanFactoryAware, SmartInitializingSingleton {
private final CacheInterceptor cacheInterceptor = new CacheInterceptor();
@Override
public void afterSingletonsInstantiated() {
this.cacheInterceptor.afterSingletonsInstantiated();
}
}
通过配置 CacheInterceptor
类,可以拦截 @Cacheable
、@CachePut
、@CacheEvict
等注解的使用,来实现缓存的读取、更新和清除操作,实现缓存功能的切面逻辑。
ContextLifecycleScheduledTaskRegistrar
源码解析
@Override
public void afterSingletonsInstantiated() {
scheduleTasks();
}
进入上面的scheduleTasks()
方法,它又调用了ScheduledTaskRegistrar
类中的如下方法:
protected void scheduleTasks() {
//检查 taskScheduler 是否为空。为空,表示尚未配置任务调度器,需要进行初始化
if (this.taskScheduler == null) {
//创建一个单线程的调度器执行器(newSingleThreadScheduledExecutor())作为本地执行器(localExecutor)。
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
//使用本地执行器初始化一个并发任务调度器(ConcurrentTaskScheduler),并将其赋值给 taskScheduler。
this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
//如果触发器任务列表不为空
if (this.triggerTasks != null) {
//遍历配置的触发器任务列表,为每个触发器任务调用 scheduleTriggerTask() 方法进行调度,并将结果添加到任务列表中。
for (TriggerTask task : this.triggerTasks) {
addScheduledTask(scheduleTriggerTask(task));
}
}
//如果cron时间表达式列表不为空
if (this.cronTasks != null) {
//遍历配置的触发器任务列表,为每个触发器任务调用 scheduleTriggerTask() 方法进行调度,并将结果添加到任务列表中。
for (CronTask task : this.cronTasks) {
addScheduledTask(scheduleCronTask(task));
}
}
//如果固定时间任务列表不为空
if (this.fixedRateTasks != null) {
//遍历配置的固定频率任务列表,为每个固定频率任务调用 scheduleFixedRateTask() 方法进行调度,并将结果添加到任务列表中。
for (IntervalTask task : this.fixedRateTasks) {
addScheduledTask(scheduleFixedRateTask(task));
}
}
//如果固定延迟任务列表不为空
if (this.fixedDelayTasks != null) {
//遍历配置的固定延迟任务列表,为每个固定延迟任务调用 scheduleFixedDelayTask() 方法进行调度,并将结果添加到任务列表中。
for (IntervalTask task : this.fixedDelayTasks) {
addScheduledTask(scheduleFixedDelayTask(task));
}
}
}
作用:根据配置的触发器任务、Cron 任务、固定频率任务和固定延迟任务,通过任务调度器
进行任务的调度,并将调度结果保存到任务列表中。这样,可以实现定时任务的执行和调度管理。
DefaultJCacheOperationSource
源码
@Override
public void afterSingletonsInstantiated() {
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized");
}
进入上面的getDefaultCacheResolver()
@Override
protected CacheResolver getDefaultCacheResolver() {
//通过调用 getCacheResolver() 方法检查当前是否已经设置了缓存解析器
if (getCacheResolver() == null) {
//如果当前没有设置缓存解析器
//通过调用 getDefaultCacheManager() 方法获取默认的缓存管理器,
//并使用默认的缓存管理器初始化一个简单的缓存解析器(SimpleCacheResolver),
//最后封装到 SingletonSupplier 对象中
this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(getDefaultCacheManager()));
}
//取得是this.cacheResolver
return getCacheResolver();
}
具体来说,代码的逻辑如下:
- 首先,通过调用
getCacheResolver()
方法检查当前是否已经设置了缓存解析器。 - 如果当前没有设置缓存解析器(
getCacheResolver()
返回null
),则进行下一步处理。 - 通过调用
getDefaultCacheManager()
方法获取默认的缓存管理器(CacheManager
)。 - 然后,使用默认的缓存管理器初始化一个简单的缓存解析器(
SimpleCacheResolver
)。 - 将简单的缓存解析器封装到
SingletonSupplier
对象中,以确保每次调用getDefaultCacheResolver()
方法时都返回同一个缓存解析器实例。 - 将封装后的缓存解析器赋值给
cacheResolver
属性。 - 最后,返回缓存解析器(也就是
cacheResolver
属性)。
作用:
获取默认的缓存解析器。如果当前没有设置缓存解析器,则创建一个简单的缓存解析器,并将其封装到
SingletonSupplier
中,以确保每次调用该方法时都返回相同的缓存解析器实例。这样可以提供一个默认的缓存解析器,用于解析和管理缓存注解。
EventListenerMethodProcessor
EventListenerMethodProcessor
类的afterSingletonsInstantiated
方法
作用:在 Spring 容器中所有的单例 bean 实例化完成后进行回调。在这个方法中,EventListenerMethodProcessor
将会检查 Spring 容器中所有的 bean,找出标注了 @EventListener
注解的方法,然后将这些方法注册为事件监听器。
源码
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
//进行断言,确保 beanFactory 不为空。
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
//使用 beanFactory 获取所有注册的 bean 名称,并保存到 beanNames 数组中。
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
//遍历 beanNames 数组,对每个 bean 进行处理。
for (String beanName : beanNames) {
//在处理过程中,首先排除掉代理对象(Scoped Proxy),只处理原始的、非代理的 bean。
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
//通过 determineTargetClass 方法获取bean的目标类。如果无法获取目标类,则忽略该bean,进行下一个循环
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);
}
}
//determineTargetClass 方法能获取bean的目标类
if (type != null) {
//判断目标类是否是 ScopedObject 的子类
if (ScopedObject.class.isAssignableFrom(type)) {
try {
//获取目标 bean 的名称,并再次尝试获取目标类
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 {
//处理标注了 @EventListener 注解的方法,并将其注册为事件监听器。
//此方法中有判断bean中是否有EventListener.class,也就是是否使用`@EventListener` 注解
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
总结来说,EventListenerMethodProcessor
中的 afterSingletonsInstantiated
方法的作用是在所有单例 bean 实例化完成后,将标注了 @EventListener
注解的方法注册为事件监听器。这样,当相应的事件发生时,会自动调用这些事件监听器方法进行处理。
MBeanExporter
MBeanExporter
的afterSingletonsInstantiated
方法
作用:在所有单例 bean 实例化完成后,将标注了 @ManagedResource
注解的 bean 注册为 MBean,从而可以通过管理工具来管理和监控这些 bean。这样可以实现对 Spring 管理的 bean 的监控和管理功能。
源码
@Override
public void afterSingletonsInstantiated() {
try {
logger.debug("Registering beans for JMX exposure on startup");
registerBeans();
registerNotificationListeners();
}
catch (RuntimeException ex) {
// Unregister beans already registered by this exporter.
unregisterNotificationListeners();
unregisterBeans();
throw ex;
}
}
MBeanExporter
类是 Spring 框架中用于将 Spring 管理的 bean 注册为 MBean(管理 Bean)的关键组件。afterSingletonsInstantiated
方法是在所有单例 bean 实例化完成后,执行注册 MBean 的逻辑。
具体来说,afterSingletonsInstantiated
方法的作用如下:
- 在 Spring 容器中的所有单例 bean 实例化完成后,Spring 容器会调用
afterSingletonsInstantiated
方法。 - 在这个方法中,
MBeanExporter
会遍历所有的 bean,检查是否标注了@ManagedResource
注解。 - 如果发现标注了
@ManagedResource
注解的 bean,MBeanExporter
会使用MBeanExporter
的方法将该 bean 注册为 MBean。 - 注册 MBean 的过程包括生成 MBean 的名称、创建 MBean 实例、设置 MBean 的属性和操作等。
- 注册完成后,该 bean 就可以通过管理工具(如 JConsole、JVisualVM)来管理和监控。
- 如果 bean 没有标注
@ManagedResource
注解,或者标注了@ManagedResource
注解但没有配置objectName
属性,则不会进行 MBean 的注册。
总结来说,MBeanExporter
类的 afterSingletonsInstantiated
方法的作用是在所有单例 bean 实例化完成后,将标注了 @ManagedResource
注解的 bean 注册为 MBean,从而可以通过管理工具来管理和监控这些 bean。这样可以实现对 Spring 管理的 bean 的监控和管理功能。
ScheduledAnnotationBeanPostProcessor
ScheduledAnnotationBeanPostProcessor
的afterSingletonsInstantiated
方法
作用:根据是否运行在 ApplicationContext
中来决定是否要提前注册和启动定时任务。如果不是在 ApplicationContext
中运行,则调用 finishRegistration()
方法完成定时任务的注册和启动。这样可以确保在非 Spring 环境中也能正常注册和启动定时任务。
虽然非 Spring 环境本身不是基于 Spring 框架构建的,但仍然可以在非 Spring 环境中使用 Spring 框架的代码。这是因为 Spring 框架提供了许多独立于 Spring 容器的功能和组件,可以在任何 Java 应用程序中使用。
以下是一些在非 Spring 环境中使用 Spring 框架代码的常见场景:
- 使用 Spring 的依赖注入(Dependency Injection)功能:通过在非 Spring 环境中手动创建和配置 Spring 容器,可以使用 Spring 的依赖注入功能来管理对象之间的依赖关系。
- 使用 Spring 的事务管理功能:在非 Spring 环境中,可以使用 Spring 的事务管理功能来管理数据库事务,确保数据一致性和完整性。
- 使用 Spring 的数据访问功能:Spring 提供了对数据库访问的支持,包括 JDBC、ORM(如 Hibernate、MyBatis)等,可以在非 Spring 环境中使用这些功能来简化数据库操作。
- 使用 Spring 的 AOP(面向切面编程)功能:Spring 的 AOP 功能可以在非 Spring 环境中使用,实现横切关注点的模块化和复用。
- 使用 Spring 的测试支持:Spring 提供了丰富的测试支持,包括单元测试、集成测试等,可以在非 Spring 环境中使用这些功能来进行应用程序的测试。
需要注意的是,在非 Spring 环境中使用 Spring 框架的代码时,需要手动创建和配置 Spring 容器,以及确保正确地加载和使用 Spring 的相关组件和功能。
源码
@Override
public void afterSingletonsInstantiated() {
//清空 nonAnnotatedClasses 缓存,该缓存用于存储未标记为 @Scheduled 的类。
this.nonAnnotatedClasses.clear();
//检查是否在一个 ApplicationContext 中运行。如果没有运行在 ApplicationContext 中,则表示当前环境不是 Spring 应用程序,需要提前注册和启动定时任务。
if (this.applicationContext == null) {
//完成定时任务的注册和启动
finishRegistration();
}
}
与初始化后的定时任务方法
postProcessAfterInitialization
的区别
执行时机:
-
postProcessAfterInitialization
方法是在每个 bean 初始化完成后被调用,包括单例和非单例 bean。它是 Bean 后置处理器的标准方法,用于在 bean 初始化后对其进行进一步处理。 -
afterSingletonsInstantiated
方法是在所有单例 bean 实例化完成后被调用,用于在所有单例 bean 实例化完成后执行特定的逻辑。
使用前提:
postProcessAfterInitialization
方法是在spring环境内,afterSingletonsInstantiated
方法是在非spring环境下注册启动定时任务