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

目录

  • 前言
    • 阅读准备
    • 阅读指引
    • 阅读建议
  • 课程内容
    • 一、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.8.1 Supplier创建对象
        • 2.8.2 工厂方法创建对象
        • 2.8.3 构造方法创建对象
      • 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之实例化

这里说的【实例化】,是指单例的实例化,原型prototype不包含在内

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()*/@Nullabledefault 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*/@Nullabledefault 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@Nullabledefault 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 -在错误的情况下*/@Nullabledefault Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {return null;}/*** 确定要为给定bean使用的候选构造函数。* 默认实现返回null。* 参数:* beanClass—bean的原始类(不为空)beanName—bean的名称* 返回:* 候选构造函数,如果未指定,则为空* 抛出:* BeansException -在错误的情况下*/@Nullabledefault 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实例,应用后处理器,等等。

源码如下:

	@Overrideprotected 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 {// 步骤三:创建BeanObject 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为nullif (!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个步骤。步骤一就是获取类加载器,往里追踪会发现,实际上调用的是ClassUtils.getDefaultClassLoader()方法。里面的代码挺简单的,获取原则如下:(需要一点JVM底子才懂,不了解也无所谓

  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帮我们实例化了

源码如下:

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

方法解读:这里在实例化Bean的时候,采用了多种方式。如:

2.8.1 Supplier创建对象

Supplier,直译:供应商。
首先判断BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的get()得到对象。得直接使用BeanDefinition对象来设置Supplier,比如:

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setInstanceSupplier(new Supplier<Object>() {@Overridepublic Object get() {return new UserService();}
});
context.registerBeanDefinition("userService", beanDefinition);

2.8.2 工厂方法创建对象

如果没有设置Supplier,则检查BeanDefinition中是否设置了factoryMethod,也就是工厂方法,有两种方式可以设置factoryMethod,比如:
方式一:

<bean id="userService" class="com.zhouyu.service.UserService" factory-method="createUserService" />

对应的UserService类为:

public class UserService {public static UserService createUserService() {System.out.println("执行createUserService()");UserService userService = new UserService();return userService;}public void test() {System.out.println("test");}}

方式二:

<bean id="commonService" class="com.zhouyu.service.CommonService"/>
<bean id="userService1" factory-bean="commonService" factory-method="createUserService" />

对应的CommonService的类为:

public class CommonService {public UserService createUserService() {return new UserService();}
}

Spring发现当前BeanDefinition方法设置了工厂方法后,就会区分这两种方式,然后调用工厂方法得到对象。
值得注意的是,我们通过@Bean所定义的BeanDefinition,是存在factoryMethod和factoryBean的,也就是和上面的方式二非常类似,@Bean所注解的方法就是factoryMethod,AppConfig对象就是factoryBean。如果@Bean所所注解的方法是static的,那么对应的就是方式一。

2.8.3 构造方法创建对象

RT。

2.9 AbstractAutowireCapableBeanFactory#autowireConstructor:推断构造方法

方法调用链:由2.7的createBeanInstance调用过来
全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor
方法注释:推断构造方法,并且创建对象。

代码好长,我就不截取了。这里的代码看不看都还好,主要还是理解流程跟原则就好。

  1. 如果一个类只有一个构造方法,不管这个构造方法是有参还是无参,Spring都会使用这个构造方法创建对象
  2. 如果有多个构造方法,则看有没有无参构造方法。因为无参构造方法有默认的含义,若有,则选择无参的构造方法创建对象;
  3. 如果有多个构造方法,且没有无参,则看构造方法上是否有@Autowired注解,有就选择,没有就报错

额外的,在推断构造方法逻辑中除开会去选择构造方法以及查找入参对象意外,会还判断是否在对应的类中是否存在使用**@Lookup注解**了方法。如果存在则把该方法封装为LookupOverride对象并添加到BeanDefinition中。

在实例化时,如果判断出来当前BeanDefinition中没有LookupOverride,那就直接用构造方法反射得到一个实例对象。如果存在LookupOverride对象,也就是类中存在@Lookup注解了的方法,那就会生成一个代理对象。
@Lookup注解就是方法注入,使用demo如下:

@Component
public class UserService {private OrderService orderService;public void test() {OrderService orderService = createOrderService();System.out.println(orderService);}@Lookup("orderService")public OrderService createOrderService() {return null;}}

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 {@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {if (beanName.equals("user")) {beanDefinition.setInitMethodName("myInit");}}
}

PS:在Spring源码中,这个后置处理器有一个非常重要的使用场景,那就是SpringIOC【依赖注入】中的【寻找注入点】。这里会用到两个该后置处理器的实现类,AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor,分别用来实现@Autowired和@Resource【寻找注入点】的逻辑,并缓存在对象的一个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;}}}

方法解读:在处理完BeanDefinition后,Spring又设计了一个扩展点:InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation(),比如:

@Component
public class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {UserService userService = (UserService) bean;userService.test();}return true;}
}

上述代码就是对userService所实例化出来的对象进行处理。这个扩展点,在Spring源码中基本没有怎么使用。估计是为了后面拓展做准备

方法总结后

以后可能不这么写了,挺麻烦的。我这样圈关键方法跟链路的原因,纯粹是想加深自己的印象,我也不知道放出来给大伙看,你们能否学习到什么。

三、实例化逻辑流程图

在这里插入图片描述

学习总结

  1. 学习了实例化的过程
  2. 学习了实例化过程中用到的2种【Bean后置处理器】:InstantiationAwareBeanPostProcessorMergedBeanDefinitionPostProcessor以及他们内部的一些方法

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT处理日志文件

由于实际生产需要&#xff0c;软件系统的运行&#xff0c;会产生大量的日志文件&#xff0c;有时候一天就能产生超过百万条log记录&#xff0c;那么为了能够处理日志文件&#xff0c;查询并且找到我们想要的报错信息&#xff0c;因此不得不考虑怎么实现&#xff0c;打开大日志文…

CFD特性FPmarkets澳福认为了解这11种足够了

CFD在交易中很重要&#xff0c;但CFD特性很多投资者不了解&#xff0c;FPmarkets澳福认为了解这11种足够了&#xff1a; 1. 投资者通过标的资产价格价值的变化获利&#xff0c;而不拥有标的资产。 2. 差价合约交易没有固定的到期日。 3. 与期货交易类似&#xff0c;差价合约交易…

python自动化办公的一些小工具,函数组件

上一篇文章写了怎么自动化写一个月报&#xff0c;其中有很多很好用的函数组件&#xff0c;都被我封装为了函数&#xff0c;功能很好用。下面一一介绍&#xff1a; 1.添加汇总函数 输入一个pandas的数据框&#xff0c;就会返回一个加了汇总行的数据框。 def add_summary_row(d…

慎投!新增4本期刊被“On Hold”!快自查

又新增了被标记的期刊&#xff01;截至目前&#xff0c;小编从科睿唯安旗下的“Master Journal List”官网查到&#xff0c;本次新增4本ESCI期刊被标记&#xff0c;目前有8本SCIE期刊&#xff0c;1本SSCI期刊&#xff0c;13本ESCI期刊&#xff0c;共22本期刊被标记为“On Hold”…

c++游戏制作指南(四):c++实现数据的存储和读取(输入流fstream)

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f35f;欢迎来到静渊隐者的csdn博文&#xff0c;本文是c游戏制作指南的一部&#x1f35f; &#x1f355;更多文章请点击下方链接&#x1f355; &#x1f368; c游戏制作指南&#x1f3…

超声波传感器(HC-SR04)按时序图手撕驱动

目录 1、简介 2、传感器介绍 2.1 引脚介绍 2.2 时序图介绍 3、 需求与接线 3.1 任务需求 3.2 接线 4、Cubemax配置 4.1 SYS配置 4.2 RCC配置 4.3 时钟树配置 4.4 GPIO初始化 4.5 定时器配置 4.6 生成代码 5、 keil端代码编写 5.1 微妙函数封装 5.2 超声波驱动封装…

生信豆芽菜-差异基因富集分析

网址&#xff1a;http://www.sxdyc.com/enrichmentEnrich 该工具使用R 语言的clusterProfiler包对关键基因集进行GO和KEGG富集分析&#xff0c;注意这个的关键基因集可以是差异基因&#xff0c;WGCNA的module基因&#xff0c;也可以是表型相关的基因集 1、数据准备 准备一个基因…

SpringBoot系列之基于Jersey实现RESTFul风格文件上传API

前言 JAX-RS&#xff1a;JAX-RS是可以用可以用于实现RESTFul应用程序的JAVA API&#xff0c;给开发者提供了一系列的RESTFul注解Jersey&#xff1a;是基于JAX-RX API的实现框架&#xff0c;用于实现RESTful Web 服务的开源框架。 JAX-RX常用的注解&#xff1a; javax.ws.rs.Pa…

【网络编程·网络层】IP协议

目录 一、IP协议的概念 二、IP协议的报头 1、四位首部长度 2、16位总长度&#xff08;解包&#xff09; 3、8位协议&#xff08;分用&#xff09; 4、16位首部校验和 5、8位生存时间 6、32位源IP和32位目的IP 7、4位版本/8位服务类型 8、16位标识 9、3位标志 10、1…

IDEA 设置为护眼的豆沙绿

代码区域设置成护眼色 先打开 IDEA 的设置界面&#xff0c;然后按照下图按顺序店了设置就可以了 这个时候&#xff0c;可以看到&#xff0c;只有代码区域别成了护眼色&#xff0c;其他地方还是白的刺眼&#xff0c;我们来一个一个的解决掉 左侧的文件页修改为护眼色 还是先…

基于YOLOv8模型的五类动物目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的五类动物目标检测系统可用于日常生活中检测与定位动物目标&#xff08;狼、鹿、猪、兔和浣熊&#xff09;&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与…

【Vue-Router】路由传参

1. query 传参 list.json {"data": [{"name": "面","price":300,"id": 1},{"name": "水","price":400,"id": 2},{"name": "菜","price":500,"…

uniapp+uview封装小程序请求

提要&#xff1a; uniapp项目引入uview库 此步骤不再阐述 1.创建环境文件 env.js&#xff1a; let BASE_URL;if (process.env.NODE_ENV development) {// 开发环境BASE_URL 请求地址; } else {// 生产环境BASE_URL 请求地址; }export default BASE_URL; 2.创建请求文件 该…

数据结构--算法的时间复杂度和空间复杂度

文章目录 算法效率时间复杂度时间复杂度的概念大O的渐进表示法计算实例 时间复杂度实例 常见复杂度对比例题 算法效率 算法效率是指算法在计算机上运行时所消耗的时间和资源。这是衡量算法执行速度和资源利用情况的重要指标。 例子&#xff1a; long long Fib(int N) {if(N …

OpenCV-Python中的图像处理-GrabCut算法交互式前景提取

OpenCV-Python中的图像处理-GrabCut算法交互式前景提取 Python-OpenCV中的图像处理-GrabCut算法交互式前景提取 Python-OpenCV中的图像处理-GrabCut算法交互式前景提取 cv2.grabCut(img: Mat, mask: typing.Optional[Mat], rect, bgdModel, fgdModel, iterCount, mode…) img…

华为云零代码新手教学-体验通过Astro Zero快速搭建微信小程序

您将会学到 您将学会如何基于Astro零代码能力&#xff0c;DIY开发&#xff0c;完成问卷、投票、信息收集、流程处理等工作&#xff0c;还能够在线筛选、分析数据。实现一站式快速开发个性化应用&#xff0c;体验轻松拖拽开发的乐趣。 您需要什么 环境准备 注册华为云账号、实…

基于Helm管理Kubernetes应用

Kubernetes部署方式 官方提供Kubernetes部署3种方式 minikube Minikube是一个工具&#xff0c;可以在本地快速运行一个单点的Kubernetes&#xff0c;尝试Kubernetes或日常开发的用户使用。不能用于生产环境。 官方文档&#xff1a;Install Tools | Kubernetes 二进制包 从…

如何从cpu改为gpu,pytorch,cuda

1.cmd输入nvcc -V 2.得到 cuda版本后&#xff0c;去pytorch官网 3.根据自己的cuda进行选择 4.复制上述链接&#xff0c;进入cmd 5.cmd中输入activate XXX,这里的"XXX"指代自己在工程中用到的环境 6.进入后&#xff0c;将刚才链接粘贴&#xff0c;回车等待下载结束 …

Linux 基础

巩固基础&#xff0c;砥砺前行 。 只有不断重复&#xff0c;才能做到超越自己。 能坚持把简单的事情做到极致&#xff0c;也是不容易的。 linux的目录结构 linux的文件系统采用树状的目录结构&#xff0c;在此结构的最上层是根目录“/”&#xff0c; 然后在此目录下再创建其他…

Mirror网络库 | 实战

此篇为下文&#xff0c;上篇&#xff1a;Mirror网络库 | 说明 一、官方实例说明 场景名说明AdditiveLevels场景为“关卡”&#xff0c;附加形式加载AdditiveScenes加载卸载附加场景Basic基础的连接/断开&#xff0c;消息发送Benchmark服务器1000“怪物”生成性能测试Benchmark…