【Spring专题】Spring之Bean的生命周期源码解析——阶段二(IOC之实例化)

news2024/11/25 2:59:12

目录

  • 前言
    • 阅读准备
    • 阅读指引
    • 阅读建议
  • 课程内容
    • 一、SpringIOC之实例化
      • 1.1 简单回顾
      • 1.2 概念回顾
      • 1.3 核心方法讲解
    • 二、方法讲解
      • 2.1 AbstractBeanFactory#getMergedLocalBeanDefinition:合并BeanDefinition
      • 2.2 AbstractAutowireCapableBeanFactory#createBean:创建Bean
      • 2.3 AbstractAutowireCapableBeanFactory#resolveBeanClass:加载类
      • *2.4 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation:实例化前
      • 2.5 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation:【实例化前】真正干活的地方
      • 2.6 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization:第一次可能调用【初始化后】
      • 2.7 AbstractAutowireCapableBeanFactory#doCreateBean:开始实例化(包括后续的实例化过程)
      • 2.8 AbstractAutowireCapableBeanFactory#createBeanInstance:实例化
      • 2.9 AbstractAutowireCapableBeanFactory#autowireConstructor:推断构造方法
      • 2.10 AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors:BeanDefinition后置处理
      • 2.11 AbstractAutowireCapableBeanFactory#populateBean:属性注入
    • 三、实例化逻辑流程图
  • 学习总结

前言

阅读准备

由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序):

  • Spring底层核心原理解析【学习难度:★★☆☆☆
  • 手写简易Spring容器过程分析【学习难度:★★☆☆☆
  • Spring之底层架构核心概念解析【学习难度:★★★☆☆,重要程度:★★★★★
  • Bean的生命周期流程图【学习难度:☆☆☆☆☆,重要程度:★★★★★
  • Spring之Bean的生命周期源码解析——阶段一(扫描生成BeanDefinition)

(PS:特别是《Bean的生命周期流程图》,帮大家【开天眼】,先了解下流程。毕竟【通过业务了解代码,远比通过代码了解业务简单的多】!!!!)
(PS:特别是《Bean的生命周期流程图》,帮大家【开天眼】,先了解下流程。毕竟【通过业务了解代码,远比通过代码了解业务简单的多】!!!!)
(PS:特别是《Bean的生命周期流程图》,帮大家【开天眼】,先了解下流程。毕竟【通过业务了解代码,远比通过代码了解业务简单的多】!!!!)

阅读指引

我们在上一节课已经说到过了,本次Spring源码剖析的总入口是new AnnotationConfigApplicationContext("org.tuling.spring");,这里就不再重复解释了。本节课要说的内容,是SpringIOC的实例化,我们这里直接给到入口吧,调用链如下:(调用链比较深,不要纠结细枝末节

  1. AbstractApplicationContext#refresh:刷新方法,不用在意
  2. AbstractApplicationContext#finishBeanFactoryInitialization:在这里实例化所有剩余的(非lazy-init)单例
  3. DefaultListableBeanFactory#preInstantiateSingletons:在这里实例化所有剩余的(非lazy-init)单例(上面的方法,核心干活的方法就是这里)
  4. DefaultListableBeanFactory#getBean:获取Bean的方法
  5. AbstractBeanFactory#doGetBean:返回指定bean的一个实例,它可以是共享的,也可以是独立的
  6. 上面这个AbstractBeanFactory#doGetBean里面的一段局部代码写的回调方法,如下:
	// 如果是单例创建bean实例
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// Explicitly remove instance from singleton cache: It might have been put there
				// eagerly by the creation process, to allow for circular reference resolution.
				// Also remove any beans that received a temporary reference to the bean.
				destroySingleton(beanName);
				throw ex;
			}
		});
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
  1. AbstractAutowireCapableBeanFactory#createBean:这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等。

如上面的调用链所示,最后一个方法,才是我们本次要研究的核心方法。而且通过注释,我想大家也看到了,这个方法不单单干了实例化的工作,还有属性填充、各种后置处理器等。(PS:哈哈,同学们,我知道这个【实例化】调用链挺深的,但是大家不要烦恼,只要切记【不要纠结那些细枝末节】那一切都OK,我们老老实实地跟着主线来研究就好,毕竟这些才是核心)

阅读建议

  1. 看源码,切记纠结细枝末节,不然很容易陷进去。正常来说,看主要流程就好了
  2. 遇到不懂的,多看看类注释或者方法注释。Spring这种优秀源码,注释真的非常到位
  3. 如果你是idea用户,多用F11的书签功能。
    • Ctrl + F11 选中文件 / 文件夹,使用助记符设定 / 取消书签 (必备)
    • Shift + F11 弹出书签显示层 (必备)
    • Ctrl +1,2,3…9 定位到对应数值的书签位置 (必备)

课程内容

一、SpringIOC之实例化

1.1 简单回顾

大家知道,实例化的过程是怎样的吗?哈,我知道大部分的同学可能都不会知道。所以呢,我希望大家真的要有去看过《 Bean的声明周期流程图》,因为,通过【代码去理解业务】,远远比【通过业务理解代码】难得多!直接看个图吧,起码咱得知道【实例化到底干了什么,有哪些步骤】,我们才能更好的去研究。
在这里插入图片描述
如上图所示,实例化包含了:合并BeanDefinition、加载类、实例化之前、推断构造方法、实例化、BeanDefinition的后置处理、实例化后等,这些关键步骤。这就是我们本篇文章研究的核心!!

1.2 概念回顾

在这个【实例化】过程中,涉及到了一些Spring底层设计的概念,我在上一个笔记里面有大概介绍过Spring底层概念的一些讲解,不记得的同学记得回去翻一翻。
主要涉及的概念有:

  • BeanDefinition(设计图纸):BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特征
  • BeanPostProcessor(Spring重要的拓展点):Bean的后置处理器,对Bean做拓展操作。我们前面说过,BeanPostProcessor提供了【初始化前/后】两个拓展方法。但是这里,Spring内部对这个接口做了很多拓展,新增了一些继承自BeanPostProcessor的子类或者子接口。在实例化阶段,主要用到的接口如下:
    • InstantiationAwareBeanPostProcessor,直译过来就是:能感知实例化的Bean后置处理器。而这个继承自BeanPostProcessor,显然也具备这【初始化前/后】两个拓展方法。另外,通过InstantiationAwareBeanPostProcessor的名字大家也能猜到了,它肯定是具有对【实例化】阶段拓展的能力的。接口定义在后面。
    • SmartInstantiationAwareBeanPostProcessor:直译过来就是:智能的,能感知实例化的Bean后置处理器。在这个接口中,拓展了InstantiationAwareBeanPostProcessor接口,新增了几个函数,其中就包括了推断构造的实现。另外,这是一个框架内部使用接口。接口定义在后面。
    • MergedBeanDefinitionPostProcessor:直译过来就是:合并BeanDefinition的后置处理器。运行时用于合并bean定义的后处理器回调接口。接口定义在后面。

InstantiationAwareBeanPostProcessor接口定义如下:

/**
 * BeanPostProcessor的子接口,用于添加实例化前回调,以及实例化后但显式属性设置或自动生成之前的回调。
 * 通常用于抑制特定目标bean的默认实例化,例如创建具有特殊TargetSources的代理(池化目标、惰性初始化目标等),或者实现额外的注入策略,如字段注入。
 * 注:此接口为专用接口,主要供框架内部使用。建议尽可能实现普通的BeanPostProcessor接口。
 * 自:
 * 1.2
 * 参见:
 * org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.setCustomTargetSourceCreators, org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator
 * 作者:
 * 于尔根·霍勒,罗德·约翰逊
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	/**
	 * 在目标bean实例化之前应用这个BeanPostProcessor。返回的bean对象可能是要使用的代理而不是目标bean,从而有效地抑制目标bean的默认实例化。
	 * 如果此方法返回一个非空对象,则bean创建过程将会中断。应用的唯一进一步处理是来自配置的BeanPostProcessors的postProcessAfterInitialization回调。
	 * 这个回调将应用于带有bean类的bean定义,以及工厂方法定义,在这种情况下,返回的bean类型将在这里传递。
	 * 后置处理器可以实现扩展的SmartInstantiationAwareBeanPostProcessor接口,以便预测它们将在这里返回的bean对象的类型。
	 * 默认实现返回null。
	 * 参数:
	 * beanClass——要实例化的bean的类
	 * beanName—bean的名称
	 * 返回:
	 * 要公开的bean对象,而不是目标bean的默认实例,或者为空,继续进行默认实例化
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 参见:
	 * postProcessAfterInstantiation, org.springframework.beans.factory.support.AbstractBeanDefinition.getBeanClass(), org.springframework.beans.factory.support.AbstractBeanDefinition.getFactoryMethodName()
	 */
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	/**
	 * 在bean通过构造函数或工厂方法实例化之后,但在Spring属性填充(来自显式属性或自动装配)发生之前执行操作。
	 * 这是在Spring自动装配开始之前对给定bean实例执行自定义字段注入的理想回调。
	 * 默认实现返回true。
	 * 参数:
	 * Bean—已创建的Bean实例,其属性尚未设置
	 * beanName—bean的名称
	 * 返回:
	 * 如果应该在bean上设置属性,则为True;如果应该跳过属性人口,则为False。正常的实现应该返回true。返回false还将阻止在此bean实例上调用任何后续的InstantiationAwareBeanPostProcessor实例。
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 参见:
	 * postProcessBeforeInstantiation
	 */
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	/**
	 * 在工厂将给定的属性值应用到给定的bean之前,对它们进行后处理,不需要任何属性描述符。
	 * 如果实现提供自定义postProcessPropertyValues实现,则应该返回null(默认值),否则则返回pvs。在该接口的未来版本中(删除了postProcessPropertyValues),默认实现将直接返回给定的pv。
	 * 参数:
	 * PVS—工厂将要应用的属性值(永远不会为空)
	 * bean——已创建的bean实例,但其属性尚未设置
	 * beanName—bean的名称
	 * 返回:
	 * 应用于给定bean的实际属性值(可以是传入的PropertyValues实例),或者null,它继续处理现有属性,但特别地继续调用postProcessPropertyValues(需要为当前bean类初始化PropertyDescriptors)。
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 自:
	 * 5.1
	 * 参见:
	 * postProcessPropertyValues
	 */
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

	/**
	 * 在工厂将给定属性值应用到给定bean之前,对它们进行后处理。允许检查是否满足所有依赖项,例如基于bean属性设置器上的“Required”注释。
	 * 还允许替换要应用的属性值,通常通过基于原始PropertyValues创建新的MutablePropertyValues实例,添加或删除特定值。
	 * 默认实现按原样返回给定的pv。
	 * 弃用
	 * 从5.1开始,支持postProcessProperties(PropertyValues, Object, String)
	 * 参数:
	 * PVS—工厂将要应用的属性值(永远不会为空)
	 * PDS——目标bean的相关属性描述符(忽略了依赖类型——工厂专门处理的依赖类型——已经过滤掉了)
	 * bean——已创建的bean实例,但其属性尚未设置
	 * beanName—bean的名称
	 * 返回:
	 * 应用于给定bean的实际属性值(可以是传入的PropertyValues实例),或者为null以跳过属性填充
	 * 抛出:
	 * BeansException -在错误的情况下
	 * 参见:
	 * postProcessProperties, org.springframework.beans.MutablePropertyValues
	 */
	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}
}

SmartInstantiationAwareBeanPostProcessor接口定义如下:

/**
 *  扩展了InstantiationAwareBeanPostProcessor接口,添加了一个回调函数,用于预测被处理bean的最终类型。
 * 注:此接口为专用接口,主要供框架内部使用。一般来说,应用程序提供的后处理器应该简单地实现普通的BeanPostProcessor接口,或者从InstantiationAwareBeanPostProcessorAdapter类派生。即使在点发布版本中,也可能向该接口添加新方法。
 * 自:
 * 2.0.3
 * 参见:
 * InstantiationAwareBeanPostProcessorAdapter
 * 作者:
 * Juergen hoel
 */
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

	/**
	 * 预测这个处理器的postProcessBeforeInstantiation回调最终返回的bean的类型。
	 * 默认实现返回null。
	 * 参数:
	 * beanClass—bean的原始类beanName—bean的名称
	 * 返回:
	 * bean的类型,如果不可预测,则为空
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	@Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	/**
	 * 确定要为给定bean使用的候选构造函数。
	 * 默认实现返回null。
	 * 参数:
	 * beanClass—bean的原始类(不为空)beanName—bean的名称
	 * 返回:
	 * 候选构造函数,如果未指定,则为空
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
			throws BeansException {

		return null;
	}

	/**
	 * 获取对指定bean的早期访问的引用,通常是为了解析循环引用。
	 * 这个回调让后处理器有机会尽早公开包装器——也就是说,在目标bean实例完全初始化之前。暴露的对象应该等同于postProcessBeforeInitialization / postProcessAfterInitialization所暴露的对象。请注意,此方法返回的对象将用作bean引用,除非后处理器返回与所述后处理回调不同的包装器。换句话说:那些处理后回调可能最终公开相同的引用,或者返回那些后续回调的原始bean实例(如果受影响的bean的包装器已经为对该方法的调用构建了,那么默认情况下它将作为最终bean引用公开)。
	 * 默认实现按原样返回给定的bean。
	 * 参数:
	 * bean—原始bean实例beanName—bean的名称
	 * 返回:
	 * 要作为bean引用公开的对象(通常将传入的bean实例作为默认值)
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

MergedBeanDefinitionPostProcessor接口定义如下:

/**
 * 运行时用于合并bean定义的后处理器回调接口。BeanPostProcessor实现可以实现这个子接口,以便对合并的bean定义(原始bean定义的处理副本)进行后处理,Spring BeanFactory使用合并的bean定义来创建bean实例。
 * 例如,postProcessMergedBeanDefinition方法可以对bean定义进行内省,以便在对bean的实际实例进行后处理之前准备一些缓存的元数据。也允许修改bean定义,但只允许修改用于并发修改的定义属性。本质上,这只适用于在RootBeanDefinition本身上定义的操作,而不适用于其基类的属性。
 * 自:
 * 2.5
 * 参见:
 * org.springframework.beans.factory.config.ConfigurableBeanFactory.getMergedBeanDefinition
 * 作者:
 * Juergen hoel
 */
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

	/**
	 * 对指定bean的给定合并bean定义进行后处理。
	 * 参数:
	 * beanDefinition—为bean合并的bean定义beanType—托管bean实例的实际类型beanName—bean的名称
	 * 参见:
	 * AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors
	 */
	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

	/**
	 * 通知指定名称的bean定义已被重置,并且此后处理器应清除受影响bean的所有元数据。
	 * 默认实现为空。
	 * 参数:
	 * beanName—bean的名称
	 * 自:
	 * 5.1
	 * 参见:
	 * DefaultListableBeanFactory.resetBeanDefinition
	 */
	default void resetBeanDefinition(String beanName) {
	}
}

这里还是有一点想要提醒各位的,BeanPostProcessor是被Spring定义为【钩子】的,而钩子,很多时候都是为了改变系统原有行为的。这种改变,通常体现在:对Bean生命周期的影响,或者某个生命周期完成对象的改变等等。(这么说有点晦涩难懂,通俗点讲就是:Bean可能不会经过完整生命周期,比如【实例化前】之后,直接就跳到【初始化后】了,没有经过原本定义的【实例化】、【实例化后】、【其他后置处理】等;或者,原本初始化动作是Spring帮我门完成的,但是由于我们自己介入了,Spring就不帮我们初始化了,而是按照程序员意愿)

文章链接:
《【Spring专题】Spring之底层架构核心概念解析》

1.3 核心方法讲解

整个IOC实例化的主干过程,主要涉及了【2个类,11个核心方法】。下面,我们将会按照调用次序,依次讲解各个方法。

二、方法讲解

我们在上面说到过,这里的实例化过程包含了:合并BeanDefinition、加载类、实例化之前、推断构造方法、实例化、BeanDefinition的后置处理、实例化后等关键步骤。所以,在整个调用链上,基本上就是干了这些事情。
我们前面说过,本次的实例化代码入口如下:

	// 如果是单例创建bean实例
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// Explicitly remove instance from singleton cache: It might have been put there
				// eagerly by the creation process, to allow for circular reference resolution.
				// Also remove any beans that received a temporary reference to the bean.
				destroySingleton(beanName);
				throw ex;
			}
		});
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}

2.1 AbstractBeanFactory#getMergedLocalBeanDefinition:合并BeanDefinition

方法调用链:AbstractBeanFactory#doGetBean里面调用的
全路径:org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition
方法注释:返回合并的RootBeanDefinition,如果指定的bean对应于子bean定义,则遍历父bean定义。

我们在上节课最后的地方提到过这个,这边就不重复讲了,但是,他是算在实例化过程里面的,嘻嘻

2.2 AbstractAutowireCapableBeanFactory#createBean:创建Bean

方法调用链:AbstractBeanFactory#doGetBean里面调用的
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
方法注释:这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等。

源码如下:

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// 步骤一:加载类
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// 不用管这个
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// 步骤二:实例化前
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// 步骤三:创建Bean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

方法解读:上面代码老长一段,trt-catch占了一半,啊哈哈。 这里面的步骤就三个,下面也会讲到。

  1. resolveBeanClass:加载类
  2. resolveBeforeInstantiation:实例化前
  3. doCreateBean:真正创建Bean的地方

2.3 AbstractAutowireCapableBeanFactory#resolveBeanClass:加载类

PS:不算很重要,知道有这个步骤就好

方法调用链:由2.2的createBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeanClass
方法注释:这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等。

源码如下:

protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
		throws CannotLoadBeanClassException {
	if (mbd.hasBeanClass()) {
		return mbd.getBeanClass();
	}
	if (System.getSecurityManager() != null) {
		return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
				() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
	}
	else {
		return doResolveBeanClass(mbd, typesToMatch);
	}
}

方法解读:这个代码外层挺简单的,也许大家对比System.getSecurityManager() != null这个比较难理解而已。这是Spring内部的一个安全管理器,很多时候都是不开启的。后面也会出现大量这种代码,反正遇到这个就直接看else的逻辑就好了。至于里层的doResolveBeanClass源码如下:

    private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
            throws ClassNotFoundException {

        // 步骤一:获取默认的类加载器
        ClassLoader beanClassLoader = getBeanClassLoader();
        ClassLoader dynamicLoader = beanClassLoader;
        boolean freshResolve = false;

        // 步骤二:在我们这个调用链上不会走这里,因为typesToMatch为null
        if (!ObjectUtils.isEmpty(typesToMatch)) {
            ClassLoader tempClassLoader = getTempClassLoader();
            if (tempClassLoader != null) {
                dynamicLoader = tempClassLoader;
                freshResolve = true;
                if (tempClassLoader instanceof DecoratingClassLoader) {
                    DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                    for (Class<?> typeToMatch : typesToMatch) {
                        dcl.excludeClass(typeToMatch.getName());
                    }
                }
            }
        }

        // 步骤三
        String className = mbd.getBeanClassName();
        if (className != null) {

            // 步骤3.1:这里也不用怎么看,这是Spring表达式解析的东西。Spring表达式这个东西我们用的很少(类似EL表达式,这样来理解)
            Object evaluated = evaluateBeanDefinitionString(className, mbd);
            if (!className.equals(evaluated)) {
                if (evaluated instanceof Class) {
                    return (Class<?>) evaluated;
                }
                else if (evaluated instanceof String) {
                    className = (String) evaluated;
                    freshResolve = true;
                }
                else {
                    throw new IllegalStateException("Invalid class name expression result: " + evaluated);
                }
            }
            if (freshResolve) {
                if (dynamicLoader != null) {
                    try {

                        // 步骤3.2 加载类
                        return dynamicLoader.loadClass(className);
                    }
                    catch (ClassNotFoundException ex) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                        }
                    }
                }
                return ClassUtils.forName(className, dynamicLoader);
            }
        }

        // 步骤四:正常来说走的是这里。使用默认的类加载器加载类
        return mbd.resolveBeanClass(beanClassLoader);
    }

方法解读:在这里,大体分为4个步骤。步骤一就是获取类加载器。这个获取类加载器的原则呢,是这样的:

  1. 优先返回当前线程中的ClassLoader
  2. 线程中类加载器为null的情况下,返回ClassUtils类的类加载器
  3. 如果ClassUtils类的类加载器为空,那么则表示是Bootstrap类加载器加载的ClassUtils类,那么则返回系统类加载器

步骤二,就是第一个if,在我们这里的调用链上是不会进来这里的,因为typeToMatch是null;
步骤三,可看可不看,一般也不会进来这里。这是Spring表达式解析的东西。Spring表达式这个东西我估计大部分人都没用过吧…(类似EL表达式,这样来理解)
步骤四,正常来说会执行到这里,然后在这里进行类加载,并且通过反射获得class对象,代码如下所示:

	public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
		String className = getBeanClassName();
		if (className == null) {
			return null;
		}
		Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
		this.beanClass = resolvedClass;
		return resolvedClass;
	}

*2.4 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation:实例化前

(PS:终于来到这里了,这才是核心考点

方法调用链:由2.2的createBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
方法注释:应用实例化前的后处理器,解析指定bean是否存在实例化前的快捷方式。

源码如下:

	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

方法解读:代码短短的几行。首先通过hasInstantiationAwareBeanPostProcessors看看是否有InstantiationAwareBeanPostProcessors。有,则调用对应的【实例化前】方法,即applyBeanPostProcessorsBeforeInstantiation这里才是真正干活的地方,后面介绍)。
这里有一个细节,那就是applyBeanPostProcessorsBeforeInstantiation如果返回的对象不为空,则直接调用applyBeanPostProcessorsAfterInitialization,走bean的【初始化后】方法了!这啥意思???说明,==Bean的生命周期被改变了!!==而且,如果这里的Bean有值的话,外层直接返回创建成功了,不会继续往下走了,如下所示:(2.2的createBean调用处代码)

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
	return bean;
}

2.5 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation:【实例化前】真正干活的地方

方法调用链:由2.4的resolveBeforeInstantiation调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
方法注释:将InstantiationAwareBeanPostProcessors应用到指定的bean定义(通过类和名称),调用它们的postProcessBeforeInstantiation方法。如果返回不为空,则无需Spring帮我们实例化了

源码如下:

	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
		return null;
	}

方法解读:这里终于出现我们之前说的核心InstantiationAwareBeanPostProcessor。老样子,遍历所有的InstantiationAwareBeanPostProcessor,然后调用postProcessBeforeInstantiation()。这里只要找到一个InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation()返回不为空,则直接停止遍历。
这个方法其实隐含的意思是:在Spring帮我们实例化之前,Spring会先去找找看,用户有没有对当前beanName对应的class有自己的实例化想法,如果有,则Spring就不帮我们创建了。

2.6 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization:第一次可能调用【初始化后】

方法调用链:由2.4的resolveBeforeInstantiation调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
方法注释:应用初始化后方法。通常调用此方法的时候,会认为已经经过了属性填充、初始化等

源码如下:

	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

方法解读:看,这里直接获取所有BeanPostProcessor 接口,然后应用postProcessAfterInitialization()方法。这里有个空判断,是接口要求这么做的。返回null表示不想继续执行剩余的BeanPostProcessor 接口

2.7 AbstractAutowireCapableBeanFactory#doCreateBean:开始实例化(包括后续的实例化过程)

方法调用链:由2.2的createBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
方法注释:AbstractAutowireCapableBeanFactory这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等

源码很长,就不截取了。在这里个方法里面,主要干了4件事情:

  1. 实例化(推断构造方法、实例化)
  2. BeanDefinition的后置处理
  3. 属性注入(实例化后、属性注入)(对的,你没看错,【实例化后】是在属性注入这个方法里面被调用的)
  4. 初始化

方法解读:正如方法注释说的,这里【创建一个bean实例,填充bean实例,应用后处理器】等等。这意味着,在这里包含了【实例化】过程中剩余的==【推断构造方法、实例化、BeanDefinition的后置处理、实例化后等】==步骤。另外,下一个章节会说的【IOC属性填充】、【IOC-Aware回调】、【IOC初始化】等阶段入口其实也是在这个方法中

2.8 AbstractAutowireCapableBeanFactory#createBeanInstance:实例化

方法调用链:由2.7的doCreateBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
方法注释:AbstractAutowireCapableBeanFactory这个类的中心方法:创建一个bean实例,填充bean实例,应用后处理器,等等

源码如下:

 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 步骤一:再次确保类已经被加载
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        // 步骤二:使用Supplier创建对象
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }

        // 步骤三:工厂方法创建对象
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // Shortcut when re-creating the same bean...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }

        // 步骤四:推断构造方法
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // Preferred constructors for default construction?
        ctors = mbd.getPreferredConstructors();
        if (ctors != null) {
            return autowireConstructor(beanName, mbd, ctors, null);
        }

        // 步骤五:实例化
        return instantiateBean(beanName, mbd);
    }

方法解读:

2.9 AbstractAutowireCapableBeanFactory#autowireConstructor:推断构造方法

2.10 AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors:BeanDefinition后置处理

方法调用链:由2.7的doCreateBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
方法注释:将MergedBeanDefinitionPostProcessors应用于指定的bean定义,调用它们的postProcessMergedBeanDefinition方法。

源码如下:

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
		for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
			processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}

方法解读:Bean对象实例化出来之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点,即当前的MergedBeanDefinitionPostProcessors。这里的主要难点还是,这种类型的BeanPostProcessor的应用场景,可能才是大家比较关心的。那你们觉得,这里的主要应用场景应该是什么呢?其实,按照Spring的生命周期来说,他现在提供给你的拓展点,只能是【实例化】阶段后的生命周期了,毕竟过去已经发生的已经没办法改变。所以,我们可以在这里,干预【初始化】这个阶段,如下示例:

public static void main(String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
      Object newUser = context.getBean("user");
      System.out.println(newUser);
}

// 声明bean
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void myInit() {
        System.out.println("这是我自己指定的初始化方法");
    }
}

// 声明一个MergedBeanDefinitionPostProcessor,然后改变了User这个Bean的初始化方法
@Component
public class MyBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        if (beanName.equals("user")) {
            beanDefinition.setInitMethodName("myInit");
        }
    }
}

PS:在Spring源码中,AutowiredAnnotationBeanPostProcessor就是一个MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition()中会去查找注入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中(injectionMetadataCache),为依赖注入做准备。

2.11 AbstractAutowireCapableBeanFactory#populateBean:属性注入

(PS:属性注入不是我们这里需要关注的地方,但因为【实例化后】在这个方法里面,所以就只能点进来了)

方法调用链:由2.7的doCreateBean调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
方法注释:使用来自bean定义的属性值在给定的BeanWrapper中填充bean实例(属性填充/依赖注入)。

populateBean中关键源码如下:

	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}

三、实例化逻辑流程图

学习总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/878511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s ------存储卷(PV、PVC)

目录 一&#xff1a;为什么需要存储卷&#xff1f; 二&#xff1a;emptyDir存储卷 ​三&#xff1a;hostPath存储卷 四&#xff1a;nfs共享存储卷 五&#xff1a;PVC 和 PV 1、PVC 和 PV介绍 2、PV和PVC之间的相互作用遵循的生命周期 3、PV 的4 种状态 4、一个PV从创…

redis的三种集群方式

redis有三种集群方式&#xff1a;主从复制&#xff0c;哨兵模式和集群。 1.主从复制 主从复制原理&#xff1a; 从服务器连接主服务器&#xff0c;发送SYNC命令&#xff1b; 主服务器接收到SYNC命名后&#xff0c;开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所…

netty学习分享 二

操作系统IO模型与实现原理 阻塞IO 模型 应用程序调用一个IO函数&#xff0c;导致应用程序阻塞&#xff0c;等待数据准备好。如果数据没有准备好&#xff0c;一直等待….数据准备好了&#xff0c;从内核拷贝到用户空间,IO函数返回成功指示。 当调用recv()函数时&#xff0c;系…

mysql使用redis+canal实现缓存一致性

一、开启binlog日志 1.首先查看是否开启了binlog show variables like %log_bin%; 如果是OFF说明位开启 2、开启binlog日志&#xff0c;并重启mysql服务 右键我的电脑——管理——服务——MYSQL——属性 这里是my.ini地址 在[mysqld]底下添加 log-bin mysqlbinlog binlog-f…

Revit SDK: MaterialQuantities

前言 这个例子介绍了如何分类统计材质的和面积。用到的接口是 Element 的&#xff1a; // 返回 Element 中用到的材质 ICollection<ElementId> GetMaterialIds(bool returnPaintMaterials); // Element 获取某材质的体积 double GetMaterialVolume(ElementId materialI…

【JavaWeb】MySQL约束、事务、多表查询

1 约束 PRIMARY KEY 主键约束 UNIQUE 唯一约束 NOT NULL 非空约束 DEFAULT 默认值约束 FOREIGN KEY 外键约束 主键 主键值必须唯一且非空&#xff1b;每个表必须有一个主键 建表时主键约束 CREATE TABLE 表名 (字段名 字段类型 PRIMARY KEY,字段名 字段类型 );CR…

利用SimpleDateFormat或者LocalDateTime生成格式为“yyyy-MM-dd HH:mm:ss“的当前时间

java程序&#xff1a; // 利用LocalDateTime生成格式为"yyyy-MM-dd HH:mm:ss"的当前时间 DateTimeFormatter formatter DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime now LocalDateTime.now(); String time1 now.format(format…

[C++] 模板template

目录 1、函数模板 1.1 函数模板概念 1.2 函数模板格式 1.3 函数模板的原理 1.4 函数模板的实例化 1.4.1 隐式实例化 1.4.2 显式实例化 1.5 模板参数的匹配原则 2、类模板 2.1 类模板的定义格式 2.2 类模板的实例化 讲模板之前呢&#xff0c;我们先来谈谈泛型编程&am…

不用技术代码,分班查询系统怎么做?

暑假即将结束&#xff0c;新学期开始将面临分班信息公布的工作&#xff01;对于分班信息公布&#xff0c;涉及到学生的个人信息&#xff0c;包括姓名、学号、班级等。在发布这些信息时&#xff0c;必须确保数据的保密性&#xff0c;防止未经授权的人员获取到学生的个人信息。因…

vite打包优化分片打包依赖包

在开发Vue3项目时&#xff0c;我们使用vite进行构建&#xff0c;由于项目中开发的是地图大屏项目&#xff0c;依赖较多&#xff0c;为了提高用户体验减少用户等待的时间&#xff0c;对此进行优化&#xff1a; 1.本文主要说的是拆分打包的方法&#xff1a; // vite.config.ts…

java Spring Boot yml多环境拆分文件管理优化

上文 java Spring Boot yml多环境配置 我们讲了多环境开发 但这种东西都放在一起 还是非常容易暴露信息的 并且对维护来讲 也不是非常的友好 这里 我们在resources下创建三个文件 分别叫 application-pro.yml application-dev.yml application-test.yml 我们直接将三个环境 转…

ARPC 是对ARQC 解密 然后返回一个处理结果?

第一次GAC是在输入密码之前还是之后&#xff1f;我理解是在输入密码之后&#xff0c;输入密码后就需要联机了&#xff1f; 可以说第一次GAC肯定在联机之前发生&#xff1f; 在 EMV 交易流程中&#xff0c;第一次 GAC&#xff08;Generational Application Cryptogram&#xf…

手把手教学优化docker镜像构建,使构建的镜像比官网的还小巧轻便 Dockerfile

为什么要docker减小镜像&#xff1f; 在使用docekrfile文件构建docker镜像时&#xff0c;即使时安装一个比较小的应用&#xff0c;构建后也是镜像&#xff0c;小到好几百M大到几个G&#xff0c; 这样非常不利与镜像之间的传输与上传到镜像仓库&#xff0c;部署的时候也会浪费时…

react入门到实战 学习笔记1 搭建

一、React是什么 一个专注于构建用户界面的 JavaScript 库&#xff0c;和vue和angular并称前端三大框架 React有什么特点 1- 声明式UI&#xff08;JSX&#xff09; 写UI就和写普通的HTML一样&#xff0c;抛弃命令式的繁琐实现 2- 组件化 组件是react中最重要的内容&#xf…

插槽Slot的作用和基本使用;具名插槽的使用;作用域插槽Slot使用;全局事件总线使用;依赖注入Provide/Inject

目录 1_插槽Slot的作用1.1_认识插槽Slot1.2_如何使用插槽slot1.3_插槽的默认内容1.4_多个插槽的效果 2_插槽Slot基本使用3_具名插槽的使用4_作用域插槽Slot使用4.1_渲染作用域4.2_认识作用域插槽4.3_独占默认插槽的缩写 5_全局事件总线使用5.1_全局事件总线mitt库5.2_使用事件总…

Java多线程编程中的线程间通信

Java多线程编程中的线程间通信 基本概念&#xff1a; ​ 线程间通信是多线程编程中的一个重要概念&#xff0c;指的是不同线程之间如何协调和交换信息&#xff0c;以达到共同完成任务的目的。 线程间通信的目的 ​ 是确保多个线程能够按照一定的顺序和规则进行协作&#xff…

二、linux虚拟机配置中文输入法和如何下载软件

&#xff08;一&#xff09;配置中文输入法&#xff1a; 1、sudo apt-get install fcitx&#xff0c;安装fcitx框架&#xff0c;安装完成之后&#xff0c;选择该框架 2、接下来输入sudo apt-get install fcitx fcitx-googlepinyin&#xff0c;安装谷歌输入法之后&#xff0c;重…

分布式 - 消息队列Kafka:Kafka 消费者消息消费与参数配置

文章目录 1. Kafka 消费者消费消息01. 创建消费者02. 订阅主题03. 轮询拉取数据 2. Kafka 消费者参数配置01. fetch.min.bytes02. fetch.max.wait.ms03. fetch.max.bytes04. max.poll.records05. max.partition.fetch.bytes06. session.timeout.ms 和 heartbeat.interval.ms07.…

ubuntu环境上搭建ros2

环境搭建 设置系统区域。 首先需要确保安装环境支持 UTF-8 格式 sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALLen_US.UTF-8 LANGen_US.UTF-8 export LANGen_US.UTF-8 locale添加 ROS2 的代码仓库 设置你的sources.list&#xff0…

leetcode 面试题 02.05 链表求和

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;面试题 02.05 链表求和 ps&#xff1a; 首先定义一个头尾指针 head 、tail&#xff0c;这里的 tail 是方便我们尾插&#xff0c;每次不需要遍历找尾&#xff0c;由于这些数是反向存在的&#xff0c;所以我们直接加起来若…