Spring Bean 的生命周期

Spring Bean 的生命周期

参考源码及网络资料的个人学习笔记,欢迎大家指正错误。
源码版本`SpringBoot-2.7.2`

大致的生命周期概括

大体过程为: 实例化 --》 属性赋值 --》 初始化 --》 销毁,但在其中涉及复杂的过程及细节:

  1. 启动spring容器,创建beanFactory,用来创建与管理Bean。一般用的是Applicationcontext(ApplicationContextBeanFactory 的子接口,它继承了 BeanFactory 的功能,并且提供了更多的企业级功能,如国际化支持、事件发布、AOP、事务管理等)

    然后通过Applicationcontext加载配置文件,或者利用注解扫描的方式将bean的配置信息加载到spring容器里面。

  2. 加载之后,spring容器会将这些配置信息(java bean的信息),根据不同的配置方式,封装成BeanDefinition对象。

  3. 然后将这些BeanDefinition对象以key为beanName,值为BeanDefinition对象的形式存入到一个map里面,将这个map传入到spring beanfactory去进行springBean的实例化。

  4. 进入实例化阶段,先在实例化之前执行InstantiationAwareBeanPostProcessor 接口的 postProcessBeforeInstantiation 方法做springBean实例化之前的扩展

  5. 调用SmartInstantiationAwareBeanPostProcessor 接口的 determineCandidateConstructors方法,确定实例化bean要使用的构造函数。

  6. 通过构造函数来创建bean实例,也就是进行实例化。

  7. 实例化之后,调用MergedBeanDefinitionPostProcessor 接口的 postProcessMergedBeanDefinition 方法,对BeanDefinition进行扩展修改。

    spring中已包括:处理自动装配注解(如@Autowired@Value等)、处理通用注解(如@Resource@PostConstruct@PreDestroy等)、处理bean的初始化及销毁相关(如**@PostConstruct** 和 **@PreDestroy**等)、处理@Scheduled@Required注解等。主要是将这些注解对应的处理信息修改到bean定义中,用于后续生效。

  8. 调用SmartInstantiationAwareBeanPostProcessorgetEarlyBeanReference方法,获取一个早期的、还没有进行属性赋值初始化的bean,缓存起来用于解决循环依赖的问题。

  9. 接下来马上进行属性赋值阶段,调用InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation方法,做bean属性赋值之前的扩展操作,或自定义实现属性赋值逻辑。

  10. 调用InstantiationAwareBeanPostProcessorpostProcessProperties方法,在Bean属性赋值之前对Bean的属性值进行进一步的定制和修改。

  11. AbstractAutowireCapableBeanFactory 类中的populateBean方法中调用applyPropertyValues方法,进行属性赋值,将给定的属性值应用到指定的 bean 中。

  12. 属性赋值完成后,进入初始化之前的阶段,调用BeanPostProcessorpostProcessBeforeInitialization方法,允许开发者在Bean初始化之前对Bean进行自定义的处理操作。

    现有实现包括:ApplicationContext上下文配置、初始化之前的bean验证、引导Spring应用程序的上下文注入、@ConfigurationProperties注解处理、@Import注解的处理、错误页配置等。

  13. 正式进行bean初始化,在AbstractAutowireCapableBeanFactory类中调用afterPropertiesSet方法。不同的bean初始化逻辑不同。

  14. 调用BeanPostProcessorpostProcessAfterInitialization方法,进行bean初始化后的扩展操作

    spring现有的实现包括:aop动态代理创建、bean初始化后的验证、@Scheduled定时任务的创建执行等。

  15. 执行registerDisposableBeanIfNecessary方法,如果bean有销毁方法,将bean注册为可销毁bean,即在容器关闭后会调用bean的销毁方法。

  16. 调用SmartInitializingSingletonafterSingletonsInstantiated方法,在所有单例 bean 初始化完成后再进行一些特定的扩展操作,可自定义进行扩展。

    现有spring实现包括:创建缓存管理及解析器,提供缓存功能的支持;提供在非spring环境下,创建与调度定时任务;注册事件监听器;创建MBean,实现对 Spring 管理的 bean 的监控和管理功能。

BeanDefinition

先介绍bean定义,因为先有BeanDefinition,然后才有bean

简介

在我们通过注解、xml其他配置方式编写bean后,spring在启动时会扫描这些配置, 生成BeanDefinition,并用其来构建出这些bean。所以说,Spring是根据BeanDefinition来创建Spring bean的。

BeanDefinition是一个接口:

image-20231010102527044

BeanDefinition的代码中,包含bean定义的相关属性,如bean的类名、作用域、是否懒加载、依赖关系等:

image-20231010102427831

  • 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是父接口:

image-20231010101009304

下面介绍几种实现:

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 实现类,可以用于注解、包扫描等配置方式。

image-20231010110645799

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再调用AbstractBeanFactorygetBean 方法的 doGetBean方法:

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

doGetBean方法调用 AbstractAutowireCapableBeanFactorycreateBean 方法中的

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实例化、初始化就不执行了。

源码

位于AbstractAutowireCapableBeanFactorycreateBean 方法中,在 doCreateBean 创建bean之前,会执行:

image-20230929145920406

//给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属性

beforeInstantiationResolvedRootBeanDefinition类的属性,用于表示一个 bean 在实例化之前是否已经进行了方法重写解析。

方法重写可以在 Spring 容器中使用 lookup-methodreplaced-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方法

AbstractAutowireCapableBeanFactorydoCreateBean 创建bean的方法中,会执行:

instanceWrapper = createBeanInstance(beanName, mbd, args);

来创建Bean实例,而其中又调用了

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

进而调用了

SmartInstantiationAwareBeanPostProcessor 接口的 determineCandidateConstructors方法:

determineCandidateConstructors这个方法是在 Bean 实例化之前的阶段执行的,主要是获取并确定要使用的构造函数。

  1. 首先,通过判断 beanClass 是否为空,并且是否存在 InstantiationAwareBeanPostProcessors(即实现了 InstantiationAwareBeanPostProcessor 接口的后置处理器)来确定是否需要进行处理。
  2. 如果 beanClass 不为空且存在 InstantiationAwareBeanPostProcessors,则遍历这些后置处理器,对于每个实现了 SmartInstantiationAwareBeanPostProcessor 接口的后置处理器 bp,调用其 determineCandidateConstructors(beanClass, beanName) 方法来获取候选的构造函数数组 ctors
  3. 如果 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;
}

总结起来,这段代码的作用是通过后置处理器来确定要使用的构造函数。

然后再看AbstractAutowireCapableBeanFactorydoCreateBean ,看创建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的其他方法

  1. predictBeanType方法的作用: predictBeanType方法用于预测Bean的类型(Class),即在实例化Bean之前能够提前确定Bean的类型。这个方法可以用于解决一些特殊情况下的类型推断问题,例如在泛型中无法确定具体类型的情况下,可以通过这个方法来明确推断类型。
  2. 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方法通常在AbstractAutowireCapableBeanFactoryresolveBeforeInstantiation方法中被调用,用于在实例化Bean之前预测并获取Bean的类型。
  • getEarlyBeanReference方法通常在AbstractAutowireCapableBeanFactorydoCreateBean方法中,Bean属性赋值之前被调用,用于提前暴露Bean的引用。在下面会说到。

这两个方法都提供了在Bean实例化过程中的扩展点,具体实现可以由开发人员根据具体的需求来提供, 在Bean实例化过程中对类型推断和提前引用进行个性化的处理。

开始Bean实例化

AbstractAutowireCapableBeanFactorycreateBeanInstance方法中

上面的determineCandidateConstructors代码解析中,如果需要进行构造注入,就用有参构造函数进行实例化,否则就是用无参构造函数实例化。

image-20231006150323388

调用完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定义的后置处理器:

image-20230930095345606

这6个实现的大致实现逻辑:

  1. AutowiredAnnotationBeanPostProcessor:这个后置处理器实现了postProcessMergedBeanDefinition方法,用于处理自动装配注解(如@Autowired@Value等)。它会检查Bean定义中是否使用了这些注解,并根据注解的信息进行自动装配或属性值注入的bean定义缓存处理。
  2. RequiredAnnotationBeanPostProcessor:这个后置处理器实现了postProcessMergedBeanDefinition方法,用于处理@Required注解。但它的postProcessMergedBeanDefinition方法体是空的。它会检查Bean定义中是否使用了@Required注解,并确保被注解的属性在容器创建Bean时必须被设置。
  3. ApplicationListenerDetector:是用于检测和处理实现了ApplicationListener接口的Bean。在它所实现的postProcessMergedBeanDefinition方法中,会对传入的RootBeanDefinition进行判断,如果该Bean定义的Bean类实现了ApplicationListener接口,那么就会将该Bean定义标记为一个ApplicationListener,并将其注册到ApplicationListenerRegistry中。以便在Spring应用上下文启动后自动触发事件监听。
  4. InitDestroyAnnotationBeanPostProcessor:用于查找Bean定义中关于初始化和销毁的相关处理信息,比如注解 @PostConstruct@PreDestroy。缓存到合并Bena定义中用于后续处理。
  5. CommonAnnotationBeanPostProcessor:这个后置处理器实现了postProcessMergedBeanDefinition方法,用于处理通用注解(如@Resource@PostConstruct@PreDestroy等,能处理初始化及销毁主机,是因为它继承了上面那个InitDestroyAnnotationBeanPostProcessor)。它会检查Bean定义中是否使用了这些注解,并根据注解的信息进行依赖注入或生命周期回调方法的bean定义缓存处理。
  6. ScheduledAnnotationBeanPostProcessor:处理带有@Scheduled注解的方法,但它的postProcessMergedBeanDefinition方法体是空的。@Scheduled`注解标记的方法会被注册为定时任务,以便在预定的时间触发执行。这样可以方便地使用注解方式来实现定时任务的调度和执行。
4.getEarlyBeanReference

SmartInstantiationAwareBeanPostProcessorgetEarlyBeanReference方法

说白了,SmartInstantiationAwareBeanPostProcessorgetEarlyBeanReference方法其实就是用来获取一个早期的、还没有进行属性赋值初始化的bean,缓存起来用于解决循环依赖的问题。

保证在循环依赖的情况下,每个Bean都能够得到一个有效的引用,从而避免了循环依赖导致的Bean无法获取的问题。

源码调用位置

AbstractAutowireCapableBeanFactorydoCreateBean方法中,在修改合并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方法体如下,实际是套了一层来调用SmartInstantiationAwareBeanPostProcessorgetEarlyBeanReference方法:

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主要有两个实现,AbstractAutoProxyCreatorMockitoPostProcessor

  • AbstractAutoProxyCreator是Spring框架提供的一个BeanPostProcessor实现,用于自动创建代理对象。当应用程序中有配置了需要进行自动代理的Bean时,AbstractAutoProxyCreator会在Bean创建阶段介入,创建代理对象,然后将代理对象返回作为早期Bean引用。
  • MockitoPostProcessor是Mockito框架提供的一个BeanPostProcessor实现,用于在测试中使用Mockito来创建模拟对象。当应用程序中有配置了需要进行Mockito处理的Bean时,MockitoPostProcessor会在Bean创建阶段介入,使用Mockito框架来创建模拟对象,然后将模拟对象返回作为早期Bean引用。

所以,MockitoPostProcessor只是用做测试使用,大部分情况下AbstractAutoProxyCreator是真正运行所需要的。

来看下AbstractAutoProxyCreatorgetEarlyBeanReference具体实现

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属性赋值阶段:

代码总览

AbstractAutowireCapableBeanFactorydoCreateBean 方法中的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

InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation方法

实例化之后,属性赋值之前:

postProcessAfterInstantiation方法作用:对属性赋值操作的扩展,或是自定义实现属性赋值

源码位置

AbstractAutowireCapableBeanFactorydoCreateBean 方法中的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);
            
	}

然后看下InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation方法实现

进入了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

InstantiationAwareBeanPostProcessorpostProcessProperties方法

作用:在Bean属性赋值之前,对Bean的属性值进行进一步的定制和修改。

通常在postProcessProperties方法中,可以执行以下操作:

  • 根据属性值的特定条件进行修改,例如根据某些配置或环境变量的值改变属性的值。
  • 添加额外的属性值,例如根据其他属性值计算得出的动态属性。
  • 删除或过滤掉不需要的属性值,以控制哪些属性需要注入。

源码位置

AbstractAutowireCapableBeanFactorydoCreateBean 方法中的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);
		}
            
	}

InstantiationAwareBeanPostProcessorpostProcessProperties方法有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所依赖,配置EnhancedConfigurationBeanFactory正是为了该@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 方法的作用有以下几点:

  1. 解析属性值中的运行时引用:对于属性值中的其他 bean 引用,会在该方法中进行解析,确保将正确的 bean 引用赋值给属性。
  2. 执行属性值的深拷贝:为了避免对原始属性值进行永久性修改,applyPropertyValues 方法会对属性值进行深拷贝操作。这样,即使在后续的操作中对属性值进行修改,原始属性值也不会受到影响。
  3. 应用属性值到 bean 对象:将解析后的属性值应用到指定的 bean 对象中,通过 BeanWrapper 对象(bw)将属性值设置到 bean 的相应属性上。
  4. 处理属性依赖关系:如果在属性值中存在对其他 bean 的依赖关系,会在应用属性值之前处理这些依赖关系,确保所依赖的 bean 先于当前 bean 实例化和初始化。
  5. 执行属性编辑器转换:如果配置了属性编辑器(PropertyEditor),会在应用属性值之前对属性进行编辑器转换。这可以将字符串类型的属性值转换为目标属性类型所需的类型。

需要注意的是,applyPropertyValues 方法是 AbstractAutowireCapableBeanFactory 的内部方法,在初始化 bean 时会被调用。它通过解析属性值的引用、深拷贝属性值、应用属性值到 bean 对象、处理属性依赖关系以及执行属性编辑器转换等操作,确保属性值正确地被设置到相应的 bean 属性中。

总结起来,applyPropertyValues 方法的主要作用是将给定的属性值应用到指定的 bean 中,通过解析引用、深拷贝属性值、处理属性依赖关系和执行属性编辑器转换等操作,确保属性值正确地设置到 bean 的相应属性中。

Bean初始化阶段:

Bean初始化之前

7.invokeAwareMethods

作用:

invokeAwareMethods方法用于处理Bean的Aware接口,根据Bean实现的具体Aware接口类型,将相应的资源或信息注入到Bean中。这样,Bean在后续的使用中可以方便地获取自己的名称、ClassLoader或BeanFactory等关键信息。

源码位置

位于初始化Bean的initializeBean方法中,在AbstractAutowireCapableBeanFactorydoCreateBean方法中调用

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 概念原理

BeanPostProcessorpostProcessBeforeInitialization方法

它的作用是在Bean初始化之前对Bean进行扩展操作,可由开发者自定义实现。 spring中也有自带的实现,在我们使用了相应的配置后进行初始化前调用,具体可以参考下方的具体实现

postProcessBeforeInitialization方法的大致做如下功能:

  1. 对Bean进行属性设置或修改:可以在该方法中对Bean的属性进行设置或修改。开发者可以根据需要,动态地修改Bean中的属性值,或者对属性进行一些额外的处理。
  2. 执行自定义的初始化逻辑:可以在该方法中执行一些自定义的初始化操作。例如,对Bean进行一些额外的初始化逻辑、资源的初始化、打开数据库连接等。
  3. 返回修改后的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 具体实现

源码中BeanPostProcessorpostProcessBeforeInitialization方法有如下实现类

image-20231002114325859

下面只介绍有具体实现的类,没有介绍的都是如下这种没有具体逻辑的,就不说了:

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可以实现以下类型的验证:

  1. 属性约束验证:通过在Bean属性上添加注解,如@NotNull@Size@Min@Max等,来定义属性的约束条件,并在BeanValidationPostProcessor中进行验证。
  2. 组验证:通过在Bean上定义验证组,可以根据不同的场景或条件进行属性验证。通过使用@GroupSequence注解,可以指定验证组的顺序。
  3. 自定义验证:使用自定义的验证注解和验证器,可以实现特定的验证逻辑。通过编写自定义的验证注解和对应的验证器,在BeanValidationPostProcessor中进行自定义验证。
  4. 嵌套属性验证:在包含关系的对象中,可以对嵌套属性进行验证。通过在嵌套属性上添加验证注解,可以对其进行验证,并在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**提供了以下主要功能和用途:

  1. 应用程序上下文的配置加载:BootstrapContext负责加载应用程序的配置,例如从属性文件、YAML文件或数据库中加载配置信息。
  2. BeanFactory的初始化:BootstrapContext用于创建和初始化BeanFactory,它是Spring应用程序上下文的核心组件之一。
  3. 环境的准备:BootstrapContext可以准备应用程序运行所需的环境,例如设置系统属性、加载外部资源等。
  4. 生命周期管理:BootstrapContext负责应用程序上下文的生命周期管理,包括创建、刷新、关闭等操作。
  5. 还可以定义项目启动前需要处理的方法

总的来说,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

如果ServletContextServletConfig可用,则将它们设置到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初始化之前,为实现了ServletContextAwareServletConfigAware接口的Bean设置相应的Servlet环境对象。它检查ServletContextServletConfig是否可用,并将它们设置到相应的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接口的具体实现类包括TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory等,分别对应使用Tomcat、Jetty和Undertow作为Web服务器的配置。

image-20231002155752697

通过使用WebServerFactory接口及其实现类,可以轻松配置和创建不同的Web服务器,并进行相应的定制,以满足应用程序的需要。

开始Bean初始化

9.afterPropertiesSet
9.1原理

此处正式执行Bean的初始化,通过invokeInitMethods方法,有spring自带的初始化方法与自定义的初始化方法:

  • 自带的初始化方法,根据不同的Bean有不同的实现。
  • 自定义的初始化方法则由开发者自己实现。

源码

位置:在AbstractAutowireCapableBeanFactoryinitializeBean中: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实例

image-20231003111427436

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

配置ObjectMapperObjectMapper是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原理

BeanPostProcessorpostProcessAfterInitialization方法

作用:在目标bean完成初始化后,对其进行额外的处理或修改。

常见的用途包括:

  1. 对目标bean的属性进行修改或校验:可以在此方法中对目标bean的属性进行一些额外的处理或校验,例如对属性进行初始化、修改或验证。
  2. 对目标bean进行代理或包装:可以在此方法中对目标bean进行代理,例如通过AOP框架对目标bean应用切面逻辑,或者通过包装器将目标bean包装在其他对象中。
  3. 对目标bean进行一些其他定制逻辑:可以根据业务需求在此方法中进行一些其他的定制逻辑,例如注册额外的监听器、设置一些属性值等。

需要注意的是,postProcessAfterInitialization方法并不负责目标bean的实例化和依赖注入,它仅在目标bean的初始化之后进行处理

源码

位置:在AbstractAutowireCapableBeanFactoryinitializeBean中。

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 具体实现

源码中BeanPostProcessorpostProcessAfterInitialization方法有如下实现

image-20231003135051780

下面只介绍有具体逻辑实现的类,没有介绍的都是如下这种没有具体实现直接返回的,就不写了:

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
}
AbstractAdvisingBeanPostProcessor

AbstractAdvisingBeanPostProcessorpostProcessAfterInitialization方法

作用:在Bean初始化完成后,对目标Bean进行增强的处理。它可以根据配置的增强规则,为目标Bean添加额外的功能(如切面、拦截器等)。

它执行两个判断:

  • 如果当前bean已经是代理bean,则将advisor(切点+通知)添加到现有代理bean的advisor链(List)中;
  • 如果当前bean不是代理bean,但满足了切面条件,则根据当前bean创建一个新的代理bean,并将advisor(切点+通知)添加到代理bean中;
  • 如果以上条件都不满足,则直接返回原始的bean对象,不进行任何代理。

源码解析

看源码之前先了解几个东西:

  1. AopInfrastructureBean

    AopInfrastructureBean是一个标记接口。若Bean实现了此接口,表明它是一个Spring AOP的基础类,那么这个类是不会被AOP给代理的,即使它能被切面切进去。

  2. Advised是不是就是标记@Aspect注解的类?

    被@Aspect注解标记的类所生成的代理对象是Advised接口的实现类,该实现类中包含@Aspect配置类中定义的切点、通知等信息。
    但并不是所有实现了Advised接口的对象都是由@Aspect注解标记的类所生成的,比如用非注解方式实现的aop也会实现Advised接口。
    
  3. 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

AbstractAutoProxyCreatorpostProcessAfterInitialization方法

作用是判断当前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,是为了确保了依赖注入和其他后处理器的正常执行,从而保证代理对象的正确创建。

AbstractAutoProxyCreatorpostProcessAfterInitialization方法中,通过wrapIfNecessary来创建了代理bean,

AbstractAdvisingBeanPostProcessorpostProcessAfterInitialization方法中,也用了相似的逻辑创建了代理bean,

那么二者有何不同呢?

它们的主要区别在于使用的场景和功能:

AbstractAdvisingBeanPostProcessor是一个用于AOP面向切面编程的后处理器。它主要用于在Bean初始化后,对目标Bean应用增强逻辑(如通知、拦截器等)。它的代理是在初始化后才创建的。

AbstractAutoProxyCreator是一个用于自动代理的后处理器。它主要用于根据一些规则自动为Bean创建代理对象,而无需显式配置。它的代理在bean实例化后就创建了,虽然在初始化后又创建了一遍,但后者是对前者的补充。

AdvisorAdapterRegistrationManager

AdvisorAdapterRegistrationManagerpostProcessAfterInitialization方法

该方法的作用是在目标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和目标对象之间进行适配。

源码中何处使用了AdvisorAdvisorAdapter

AdvisorAdapter有三个实现类:

image-20231004163021646

他们在DefaultAdvisorAdapterRegistry中被使用:

image-20231004163125130

DefaultAdvisorAdapterRegistry又是GlobalAdvisorAdapterRegistry的实例属性:

image-20231004163213726

GlobalAdvisorAdapterRegistry又在AbstractAutoProxyCreator中被使用

image-20231004163325421

AbstractAutoProxyCreatorcreateProxy方法中,创建代理bean时,会调用

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

来将 advisor切点+通知 添加到代理bean中,用于目标对象在实际被调用时的aop通知执行

关于aop代理的方法拦截器

DefaultAdvisorAdapterRegistrygetInterceptors方法:

方法拦截器是由 advisor切点+通知 转化而来的,用于切点所标记的被代理目标对象的方法执行时,进行执行拦截,从而执行我们的切面方法。

image-20231004164146401

ApplicationListenerDetector

ApplicationListenerDetectorpostProcessAfterInitialization方法

作用:将实现了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

BeanValidationPostProcessorpostProcessAfterInitialization方法

**作用:**在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可以实现以下类型的验证:

  1. 属性约束验证:通过在Bean属性上添加注解,如@NotNull@Size@Min@Max等,来定义属性的约束条件,并在BeanValidationPostProcessor中进行验证。
  2. 组验证:通过在Bean上定义验证组,可以根据不同的场景或条件进行属性验证。通过使用@GroupSequence注解,可以指定验证组的顺序。
  3. 自定义验证:使用自定义的验证注解和验证器,可以实现特定的验证逻辑。通过编写自定义的验证注解和对应的验证器,在BeanValidationPostProcessor中进行自定义验证。
  4. 嵌套属性验证:在包含关系的对象中,可以对嵌套属性进行验证。通过在嵌套属性上添加验证注解,可以对其进行验证,并在BeanValidationPostProcessor中进行嵌套属性的验证。

BeanValidationPostProcessor是Spring框架中一个用于支持JSR-303 Bean验证的后置处理器。它可以应用于使用注解进行验证的JavaBean对象上。

以下是一些常用的验证注解,可以用于BeanValidationPostProcessor进行验证的JavaBean上:

  1. @NotNull:用于验证对象是否为null。
  2. @NotEmpty:用于验证字符串、集合或数组是否为空。
  3. @NotBlank:用于验证字符串是否非空且不包含空格。
  4. @Size:用于验证字符串、集合或数组的长度是否在指定范围内。
  5. @Min:用于验证数字是否大于等于指定最小值。
  6. @Max:用于验证数字是否小于等于指定最大值。
  7. @Pattern:用于验证字符串是否匹配指定的正则表达式。
  8. @Email:用于验证字符串是否是有效的电子邮件地址。
  9. @AssertTrue:用于验证布尔类型的字段或方法是否为true。
  10. @AssertFalse:用于验证布尔类型的字段或方法是否为false。

除了以上列举的常用验证注解,还有很多其他的验证注解可以使用。这些注解可以通过在JavaBean的字段、getter或者setter方法上进行声明,以指定对应字段的验证规则。然后,在BeanValidationPostProcessor中使用这些注解进行验证,以确保JavaBean对象的数据的有效性和一致性。

JsonTestersAutoConfiguration

JsonTestersAutoConfiguration类的内部类JsonMarshalTestersBeanPostProcessorpostProcessAfterInitialization方法

作用:在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的内部类SpyPostProcessorpostProcessAfterInitialization方法

作用:在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的销毁方法。
(具体的关闭及销毁方法调用,参照ConfigurableApplicationContextclose方法)

AbstractAutowireCapableBeanFactorydoCreateBean方法最后

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

SmartInitializingSingletonafterSingletonsInstantiated方法

作用:在所有单例 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();
		}
	}

}
已有实现

image-20231007154327851

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;
}

具体来说,代码的逻辑如下:

  1. 首先,检查当前的缓存解析器(getCacheResolver())是否为空。
  2. 如果缓存解析器为空,表示缓存管理器尚未初始化,需要进行延迟初始化。
  3. 确保 beanFactory 不为空(通过断言 this.beanFactory != null)。
  4. 尝试通过 beanFactory 获取一个 CacheManager 实例,作为默认的缓存管理器。
  5. 如果存在多个 CacheManager 实例,抛出 NoUniqueBeanDefinitionException 异常,表示无法确定要使用的 CacheManager
  6. 如果没有找到 CacheManager 实例,抛出 NoSuchBeanDefinitionException 异常,表示没有找到任何可用的 CacheManager 实例。
  7. 如果成功获取到 CacheManager 实例,将其设置为当前的缓存管理器(setCacheManager())。
  8. initialized 标志设置为 true,表示初始化完成。

总结来说,这段代码的作用是在所有单例 bean 实例化完成后,检查并延迟初始化缓存管理器。通过获取 CacheManager 实例来设置缓存管理器,以确保在使用缓存功能之前,缓存解析器和缓存管理器已经准备就绪。

CacheAspectSupport类是什么,有什么用?

CacheAspectSupport 类是 Spring 框架中与缓存相关的切面支持类,用于提供缓存功能的支持。

具体来说,CacheAspectSupport 类的主要作用如下:

  1. 提供了缓存切面的基本实现,作为其他缓存切面的基类。
  2. 实现了 SmartInitializingSingleton 接口,以确保在所有单例 bean 实例化完成后进行缓存相关的初始化操作。
  3. 提供了与缓存解析器和缓存管理器相关的属性和方法,用于配置和获取缓存相关的组件。
  4. 提供了方法用于将缓存注解应用到目标方法上,实现缓存的读取、更新和清除操作。
  5. 提供了方法用于处理缓存的异常情况,如缓存读写异常、缓存注解配置错误等。
  6. 通过 CacheOperationSource 接口实现,提供了解析和管理缓存注解的能力。
  7. 提供了方法用于获取缓存统计信息,如缓存命中率、缓存命中次数等。

总的来说,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()中,发现实际上就是CacheAspectSupportafterSingletonsInstantiated方法,具体含义上面已介绍,此处不在解释。

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

具体来说,代码的逻辑如下:

  1. 首先,通过调用 getCacheResolver() 方法检查当前是否已经设置了缓存解析器。
  2. 如果当前没有设置缓存解析器(getCacheResolver() 返回 null),则进行下一步处理。
  3. 通过调用 getDefaultCacheManager() 方法获取默认的缓存管理器(CacheManager)。
  4. 然后,使用默认的缓存管理器初始化一个简单的缓存解析器(SimpleCacheResolver)。
  5. 将简单的缓存解析器封装到 SingletonSupplier 对象中,以确保每次调用 getDefaultCacheResolver() 方法时都返回同一个缓存解析器实例。
  6. 将封装后的缓存解析器赋值给 cacheResolver 属性。
  7. 最后,返回缓存解析器(也就是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

MBeanExporterafterSingletonsInstantiated方法

作用:在所有单例 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 方法的作用如下:

  1. 在 Spring 容器中的所有单例 bean 实例化完成后,Spring 容器会调用 afterSingletonsInstantiated 方法。
  2. 在这个方法中,MBeanExporter 会遍历所有的 bean,检查是否标注了 @ManagedResource 注解。
  3. 如果发现标注了 @ManagedResource 注解的 bean,MBeanExporter 会使用 MBeanExporter 的方法将该 bean 注册为 MBean。
  4. 注册 MBean 的过程包括生成 MBean 的名称、创建 MBean 实例、设置 MBean 的属性和操作等。
  5. 注册完成后,该 bean 就可以通过管理工具(如 JConsole、JVisualVM)来管理和监控。
  6. 如果 bean 没有标注 @ManagedResource 注解,或者标注了 @ManagedResource 注解但没有配置 objectName 属性,则不会进行 MBean 的注册。

总结来说,MBeanExporter 类的 afterSingletonsInstantiated 方法的作用是在所有单例 bean 实例化完成后,将标注了 @ManagedResource 注解的 bean 注册为 MBean,从而可以通过管理工具来管理和监控这些 bean。这样可以实现对 Spring 管理的 bean 的监控和管理功能。

ScheduledAnnotationBeanPostProcessor

ScheduledAnnotationBeanPostProcessorafterSingletonsInstantiated方法

作用:根据是否运行在 ApplicationContext 中来决定是否要提前注册和启动定时任务。如果不是在 ApplicationContext 中运行,则调用 finishRegistration() 方法完成定时任务的注册和启动。这样可以确保在非 Spring 环境中也能正常注册和启动定时任务。

虽然非 Spring 环境本身不是基于 Spring 框架构建的,但仍然可以在非 Spring 环境中使用 Spring 框架的代码。这是因为 Spring 框架提供了许多独立于 Spring 容器的功能和组件,可以在任何 Java 应用程序中使用。

以下是一些在非 Spring 环境中使用 Spring 框架代码的常见场景:

  1. 使用 Spring 的依赖注入(Dependency Injection)功能:通过在非 Spring 环境中手动创建和配置 Spring 容器,可以使用 Spring 的依赖注入功能来管理对象之间的依赖关系。
  2. 使用 Spring 的事务管理功能:在非 Spring 环境中,可以使用 Spring 的事务管理功能来管理数据库事务,确保数据一致性和完整性。
  3. 使用 Spring 的数据访问功能:Spring 提供了对数据库访问的支持,包括 JDBC、ORM(如 Hibernate、MyBatis)等,可以在非 Spring 环境中使用这些功能来简化数据库操作。
  4. 使用 Spring 的 AOP(面向切面编程)功能:Spring 的 AOP 功能可以在非 Spring 环境中使用,实现横切关注点的模块化和复用。
  5. 使用 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的区别

执行时机:

  1. postProcessAfterInitialization 方法是在每个 bean 初始化完成后被调用,包括单例和非单例 bean。它是 Bean 后置处理器的标准方法,用于在 bean 初始化后对其进行进一步处理。
  2. afterSingletonsInstantiated 方法是在所有单例 bean 实例化完成后被调用,用于在所有单例 bean 实例化完成后执行特定的逻辑。

使用前提:

postProcessAfterInitialization 方法是在spring环境内,afterSingletonsInstantiated 方法是在非spring环境下注册启动定时任务

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring生命周期包括实例化、配置和销毁三个阶段。首先,实例化阶段是指创建一个Bean的实例。在Spring中,Bean的实例化可以通过使用BeanFactory或ApplicationContext来获取。其次,配置阶段是指对实例化的Bean进行配置,也就是进行IOC注入。在这个阶段Spring会根据配置文件中的Bean的id值进行相应的配置。如果Bean实现了BeanNameAware接口,Spring还会调用它实现的setBeanName(String)方法,传递的参数就是Bean的id值。最后,销毁阶段是指当Bean不再使用时进行垃圾回收。对于Singleton模式的Bean,Spring会负责管理整个生命周期;而对于Prototype模式的Bean,Spring在创建好并交给使用者后就不再管理后续的生命周期。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [关于Spring Bean的生命周期](https://blog.csdn.net/Apeopl/article/details/82964799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Springbean生命周期详解](https://blog.csdn.net/qq_64169170/article/details/123052663)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值