Spring IoC Container 原理解析

本文深入探讨Spring的IoC容器,通过现实世界与虚拟世界的比喻,阐述BeanFactory和ApplicationContext的角色,以及BeanDefinition的重要性。文章详细解析了BeanFactory、BeanDefinition、BeanLifeCycle等核心概念,并通过配置类、BeanPostProcessor、InstantiationAwareBeanPostProcessor等接口的使用,揭示了Spring容器的工作原理。此外,还介绍了@Configuration、@Bean、@Import、@Autowired等注解在Spring框架中的作用。
摘要由CSDN通过智能技术生成

代码:

public void testWithSpring() throws Exception {

ApplicationContext ctx = new AnnotationConfigApplicationContext(MovieConfig.class);

MovieLister lister = (MovieLister) ctx.getBean(“movieLister”);

}

关键对象

====

为了更好的方便理解,我们尝试着将现实世界的对象一一映射到虚拟世界

现实世界

====

这里我们以饭店举例

Spring IoC Container 原理解析

几个关键的对象:

海鲜加工饭店

有自己的招牌和特色,不过注意该饭店所有食材均需要客户自带。

出单系统

客户点菜下单(到前台或者找服务员都行,因为自己带的菜还要交给饭店嘛)后自动将客户的订单打印出来,打印出来的订单除了菜名还会加上:序号、桌位号、菜品的口味等。职责就是简洁清晰的打印出订单信息,供厨师或其他人使用。

订单复核员

我们这个餐厅必须要做一个步骤,就是订单出单后再去找客户确认订单,订单确认了才能交给厨房去做,这样做的目的一来是为了避免客户误点或沟通失误,二来通过确认的沟通也提升了用户体验。

为什么我们这里这个角色叫订单复核员,而不叫服务员呢,因为我们的印象里服务员能干很多其他的事情,这样的话反而弱化了订单确认的这个关键动作。

后厨

根据送过来的食材和订单做菜,后厨关注的是如何根据订单和食材来把菜做好。

虚拟世界

====

Spring IoC Container 原理解析

直接看这个图可能会有一点懵,我们后面再详细一一进行说明和讲解,请注意,我们本章节后文都是围绕该图进行讲解,此图非常重要。

现实世界

虚拟世界

说明

海鲜加工饭店

ApplicationContext

对标海鲜加工饭店,厨房里的厨子都是他的打工仔,他制定出精美的菜单来吸引食客,@Component、@Configuration、@Bean都是它的金字招牌菜,其实就是对厨子进行了包装,且有门面吸引客源。

海鲜菜单

Java config

Spring IoC独有的招牌菜:@Component

@ComponentScan @Bean @Import等美味

后厨

BeanFactory

根据食材和订单做菜;没有饭店实体店则基本只能做点路边摊小买卖。

出单系统

BeanDefinitionRegistryPostProcessor

相当于出单系统,把客户想要的菜给转化到订单上,例如
ConfigurationClassPostProcessor将@Component @Configuration注解类转化为BeanDefinition;基于java config就离不开他

也是BeanFactoryPostProcessor的子类

订单复核员

BeanFactoryPostProcessor

确认订单信息时菜还没做,例如可以允许客户对订单做一些信息修改

订单

BeanDefinition

即订单信息,后厨要看着订单来做菜

成品

Bean

最终的产物

从上面的例子我们大致能够区分出了BeanFactory和ApplicationContext的区别。

Spring可以让我们参与到任意一个角色中:客户、海鲜加工饭店老板、出单系统、订单复核员、后厨,可以参与到其中任意环节中。

那我们可以做些什么有趣事情呢?

例如可以制定我们特色的菜单,像mybatis的@Mapper特色菜。

确认订单时给所有订单信息里加赠饮料(xml声明的bean的属性里${xx}占位符的替换)等

初步理解了这些关键对象之后,我们再深入到各个环节,看看各个环节都是怎么干的

BeanFactory

===========

给我提供订单信息和原材料我就做,订单和食材缺一不可

让我们先聚焦后厨,因为后厨是饭店的核心。

在spring framework中,Bean的生命周期在Beanfactory里就已经闭环了

ApplicationContext只是加一些料,例如扫描java config转义成BeanDefinition给到BeanFactory,然后再添加一些BeanPostProcessor等。

注意本文重点关注的是基于主流java config配置的实现,其实xml文件的配置原理也类似,不是本文重点不做探讨。

BeanFactory的生命周期是什么,其实就是用

BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor 这两个接口的实现类,往BeanFactory注册BeanDefinition和修改BeanFactory里的BeanDefinition及其他信息。

BeanDefinition

==============

订单信息在虚拟世界长什么样的?它起到了承上启下非常关键的作用。

为什么一开始要先讲BeanDefinition呢,不管基于什么配置方式都需要生成BeanDefinition,在Bean的生命周期中,第一步也是getMergedBeanDefinition。

我们先来看一下BeanDefinition的类图继承关系

Spring IoC Container 原理解析

BeanDefinition实现类与各个场景的对应,这里我们只关注java config场景的

配置场景

BeanDefinition实现类

说明

@Component及其子类,

例如:

@Configuration

@Service

AnnotatedGenericBeanDefinition

@Bean

ConfigurationClassBeanDefinition

@ComponentScan扫描到的类:

ScannedGenericBeanDefinition

RootBeanDefinition

将parentName的bean进行合并整合的结果

常用于xml配置文件声明的bean

GenericBeanDefinition

RootBeanDefinition(merged bean definition)

==========================================

Bean生命周期中最重要的BeanDefinition实现类

因为不管中间过程中是什么BeanDefinition,不管玩出什么花样

最终在bean生命周期中都会变成 RootBeanDefinition

当整合成RootBeanDefinition 后,故而spring 会给我们留了一个统一的后置处理器:

MergedBeanDefinitionPostProcessor

BeanDefinition的属性:

属性

类型

说明

parentName

ChildBeanDefinition

String

相当于java的继承父类,spring最后会把所有类型的bean都重新揉到一起形成一个新的RootBeanDefinition;

只有ChildBeanDefinition才有该属性值

beanClass

AbstractBeanDefinition

Object

可以为string 也可以为 class<?>

也可以为空,为空时基本都是要通过factoryBeanName、factoryMethodName去实例化对象

scope

String

值:

singleton

prototype

refresh (spring cloud)

默认为空,为空时就当单例处理]

singleton

详见@Scope注解;

@Scope注解的使用还是有点窍门的,例如@RefreshScope是什么原理?

lzyInit

Boolean

是否延迟加载


ApplicationContext.refresh()时不加载,getBean()时才去加载

详见@Lazy

autowireMode

AbstractBeanDefinition

int

这里其实就是DI的几种注入方式了,目前java config已经很灵活,直接注解的形式去定义就行了

AUTOWIRE_NO(默认值)

默认装配模式, 目前非xml配置都是使用这种方式,然后程序员使用注解手动注入

AUTOWIRE_BY_NAME

通过set方法,并且 set方法的名称需要和bean的name一致

AUTOWIRE_BY_TYPE

通过set方法,并且再根据bean的类型,注入属性,是通过类型配置

AUTOWIRE_CONSTRUCTOR

通过构造函数注入

Spring @Bean注解的autowire属性可以给我们去设置该属性,也能通过BeanFactoryPostProcessor去修改BeanDefinition的autowireMode;不过一般也用不到去修改这个。

@Bean因为是注解在方法上,所以是AUTOWIRE_CONSTRUCTOR

@Autowired 是在AutowiredAnnotationBeanPostProcessor里默认通过类型判断去找对应的bean,类似于AUTOWIRE_BY_TYPE,也是在这里处理@Qualifier注解的bean name查找。因为@Autowired只是一个属性值不是BeanDefinition,所有没有autowireMode属性一说

dependsOn

String[]

依赖了哪些bean,加载该bean时会先去加载依赖的bean,再来加载该bean

详见@DependsOn()

autowireCandidate

Boolean

设置当前bean在被其他对象作为自动注入对象的时候,是否作为候选bean,默认true

如果设为false则别的bean引用不到该bean

@Scoped(“”)值不为空时,bean原始的BeanDefinition会被设置为autowireCandidate =false,会新生成一个新的beanClass为代理类class的BeanDefinition设置autowireCandidate=true,即替换了掉原来的beanDefinition

primary

Boolean

设置是不是最优先的候选bean

只对使用者产生影响,对原始对象的构造不起任何影响,原始对象该生成bean还是生成;只是后面被其他地方用于时,BeanFactory去判断选择

@Primary

qualifiers

AbstractBeanDefinition

Map<String, AutowireCandidateQualifier>

Register a qualifier to be used for autowire candidate resolution, keyed by the qualifier's type name

只对使用者产生影响,对原始对象的构造不起任何影响,原始对象该生成bean还是生成;只是后面被其他地方用于时,BeanFactory去判断选择

@Qualifier 需和@Autowired一起使用

instanceSupplier

AbstractBeanDefinition

Supplier<?>

实例化对象的提供者,基本用不上自定义

isFactoryBean

RootBeanDefinition

Boolean

是否实现了FactoryBean接口,只要没实现FactoryBean接口的都是false;

factoryBeanName

String

与isFactoryBean无关

可以是任意的beanName,且不需要实现FactoryBean接口

factoryMethodName

String

与isFactoryBean无关

通过该方法取bean,需要结合factoryBeanName进行使用

constructorArgumentValues

ConstructorArgumentValues

构造函数的定义,包含参数顺序等

propertyValues

MutablePropertyValues

常用于xml声明的bean;将xml该bean的所有property标签键值对放这里;

也可以用于spring内部上下文传递一些bean的信息,就像Servlet HttpRequest.setAttribute(key,value)

initMethodName

String

初始化方法名

destroyMethodName

String

Bean销毁时触发的方法名

role

int

是由什么系统声明的bean

ROLE_APPLICATION

ROLE_SUPPORT

ROLE_INFRASTRUCTURE

description

String

Bean的描述,常用于xml配置里的<description>节点

isSingleton

boolean

判断scope.equals(“singleton”)

IsPrototype

boolean

判断scope.equals(“prototype”)

isAbstract

String

是否抽象类

FactoryBean接口相关

两种方式:

实现了spring FactoryBean接口的BeanDefinition属性isFactoryBean=true(RootBeanDefinition,merge beandefinition后可见)

例如@Configuration注解生成的bean,mybatis的mapper都是用到了FactoryBean接口的内容

注意factoryBeanName、factoryMethodName 的使用是另一种实现方式,此时isFactoryBean=false

BeanDefinitionRegistryPostProcessor

===================================

根据菜单和客户下单时的信息,生成订单给后厨

作用于BeanFactory,是BeanFactory给外界留的门,具体的执行是在ApplicationContext的生命周期里。

在spring里就是将@Configuration、@Bean等配置信息解析生成BeanDefinition注册到BeanFactory。

其继承自BeanFactoryPostProcessor

Spring IoC Container 原理解析

出单系统必须实现

BeanDefinitionRegistryPostProcessor接口方法

(ApplicationContext饭店自己也可以给后厨下单 例如

ClassPathXmlApplicationContext,就可以在applicationContext生命周期里(refresh方法内,下单给后厨之前)解析xml往Beanfactory里注册BeanDefinition)

因为也继承了BeanFactoryPostProcessor接口,所以一般也自带了确认订单的功能

例如一些典型的实现:

1、java config的关键实现类:

ConfigurationClassPostProcessor

2、mybatis的 MapperScannerConfigurer,将@Mapper接口注册成BeanDefinition

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor

注:MapperScannerConfigurer只是Mybatis mapper注入的其中一种方式

ConfigurationClassPostProcessor

===============================

**最重要的

BeanDefinitionRegistryPostProcessor实现类没有之一**

我们用的java config都是经它之手转变为BeanDefinition,因为

BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,所以也实现了postProcessBeanFactory方法。本文的重点在于IoC的过程理解,所以本章节主要还是描述该Processor源码的实现过程。

ConfigurationClassPostProcessor其postProcessBeanFactoryRegistry方法负责注册bean,将@Configuration @ComponentScan等注解解析成BeanDefinition注册到BeanFactory;postProcessBeanFactory方法负责修改BeanDefinition,将@Configuration注解的类的BeanDefinition的beanClass替换为代理后的class name。

BeanDefinitionRegistryPostProcessor也不是从石头里蹦出来的,后面ApplicationContext的生命周期会讲到是何时触发的。

postProcessBeanFactoryRegistry

==============================

循环当前所有的BeanDefinition,找那些有@Configuration注解的类进行处理,也可以有内部类,一样会去加载,不过排序是跟着外层的@Configuration一起走,@Configuration也可以加@Order注解用于将所有@Configuration的bean进行排序后按从小到大的顺序加载

也可以结合@Conditional注解使用,如果不满足Conditional条件,则不加载该Configuration

一、找到当前BeanFactory里所有@Configuration注解的BeanDefinition并通过@Order进行排序

二、循环找到的BeanDefinition,将其转化为ConfigurationClass

2.1先处理如果class有嵌套类,如果有@Configuration 或@Component 注解,同样转化为独立的ConfigurationClass

2.2 @PropertySources @PropertySource的处理,添加PropertySource至environment

2.3 @ComponentScans @ComponentScan的处理,扫描java config注解。将扫描到的class转换为BeanDefinition;然后再调用上面第一步,类似于递归调用

2.4 @Import的处理

注解value值是ImportSelector接口实现类的,直接调用接口方法selectImports拿到返回String[],class类名集合,再次去调用processImports方法

注解value值是

ImportBeanDefinitionRegistrar接口实现类的,添加至ConfigutaionClass的属性importBeanDefinitionRegistrars【关键】

注解value不是上面两种接口实现类的,直接再走判断注解转化ConfiurationClass的处理

2.5 @ImportResource的处理,添加至ConfigutaionClass的属性ImportedResource

2.6找到**@Bean**注解的method,添加至ConfigurationClass的属性beanMethod

2.7找当前class的接口,如果有@Bean注解的method,添加至ConfigurationClass的属性beanMethod(因为java8的interface有default method的存在,所以接口方法也可以生成bean)

2.8找当前class的父类,如果有@Configuration 或@Component 注解,同样转化为独立的ConfigurationClass(同嵌套类的处理)

三、将所有ConfigurationClass转换为BeanDefinition注册到BeanFactory

四、将所有ConfigurationClass的beanMethod转换为BeanDefinition注册到BeanFactory.

五、将所有ConfigurationClass的ImportedResource转换为BeanDefinition注册到BeanFactory.

六、将所有ConfigurationClass的

importBeanDefinitionRegistrars,调用其registerBeanDefinitions方法进行BeanDefinition的注册,同BeanDefinitionRegistryPostProcessor,也是用于注册BeanDefinition【关键】

另外@Conditional可以结合@Configuration、@Bean注解进行使用,不满足条件的不加载为BeanDefinition

@Configuration

@Component

public @interface Configuration {

ConfigurationClass对象关键属性(解析@Configuration、@Component注解的类后得到的结果)

属性

类型

说明

metadata

AnnotationMetadata

@Configuration

类的注解集合

beanName

String

Pojo类名

beanMethods

Set<BeanMethod>

@Bean 的方法集合

importedResources

Map<String, Class<? extends BeanDefinitionReader>>

待加载的xml配置文件

importBeanDefinitionRegistrars

Map<ImportBeanDefinitionRegistrar, AnnotationMetadata>

待加载的


ImportBeanDefinitionRegistrar接口

用于注册BeanDefinition

@Bean

=====

这里@Configuration或者@Component注解里的@Bean注解的方法,会注册为BeanDefinition,然后其BeanClass为空,factoryBeanName为其@Configuration或者@Component类的beanName;factoryMethodName就是 @Bean注解的方法名。

这里就是用到了BeanDefinition内容里的factoryBeanName和factoryMethodName进行处理,委托其他类(@Configuration类)来生成bean。

@Import

=======

对后面理解spring boot AutoConfiguration至关重要

一、注解value值是ImportSelector接口实现类的,直接调用接口方法selectImports拿到返回String[],class类名集合,再次去进行扫描

**二、注解value值是

ImportBeanDefinitionRegistrar接口实现类的,会调用其registerBeanDefinitions方法,进行BeanDefinition注册;**

等于实现了

BeanDefinitionRegistryPostProcessor的功能。

三、注解value值不是上面两种接口实现类的,直接扫描该类

Spring boot starter自动引入的核心

@EnableAutoConfiguration

public @interface SpringBootApplication {

@Import(AutoConfigurationImportSelector.class)

public @interface EnableAutoConfiguration {

public class AutoConfigurationImportSelector implements ImportSelector {

该selector会去扫描所有spring.factories文件里

org.springframework.boot.autoconfigure…EnableAutoConfiguration 属性的类

Mybatis @MapperScan

@Import(MapperScannerRegistrar.class)

Feign @EnableFeignClients

@Import(FeignClientsRegistrar.class)

这里一般都是注册的GenericBeanDefinition

postProcessBeanFactory

======================

这里涉及到AOP的知识

处理java-config相关的注解 @Configuration @ComponentScan @Import等将他们转换成BeanDefinition并注册到BeanFactory中,具体的实现也涉及到AOP知识。因为我们关注的是整体的运作流程。

将@Configuration注解转换的BeanDefinition,BeanClass属性改成 AOP代理后生成的class,这样后面bean生命周期实例化的就是代理后的class

为什么要用代理?

@Configuration

public class MovieConfiguration {

@Bean

public MovieLister movieListener(){

return new MovieLister (this.movieFinder ());

}

@Bean

public MovieFinder movieFinder(){

return new ColonDelimitedMovieFinder (“movies1.txt”);

}

}

而且此处通过AOP增强后,也不会面临内部方法调用AOP失效的问题(为什么?movieListener这里面调用movieFinder不是已经在super class了吗,其实并不是,这个父类其实也是被代理的,cglib的实践,因为只要是@Bean注解的方法都被代理拦截了,如果方法名没被代理的话,那就真是直接执行super的原始代码),如上最后movieListener里的movieFinder属性,和下面movieFinder方法生成的bean,是同一个bean;感兴趣的可以去看看源码

如何查看cglib增强后的代码,可以再main函数第一行加上如下设置即可

public static void main(String[] args) {

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,“C://”);

@Component注解(包括其子类@Service @Controller)的类也可以声明 @Bean,区别是什么呢,就是是LITE 轻量模式,不会像上面这样生成代理(@Configuration是FULL模式),即上面的 movieListenner里的movieFinder对象和 BeanFactory里的bean movieFinder 是两个不同的对象。

BeanFactoryPostProcessor

========================

有个客户突然跑过来后厨说 我刚刚下单忘了说清蒸鲈鱼不要鱼

接单后可以对订单做的事情,主要是对订单的修改,取消基本上不可能的,就像你到饭店吃饭,中途想问问服务员有个菜没做的话能不能帮我退掉,这时候服务员肯定给你讲正在做了不能退了。

作用于BeanFactory,是BeanFactory给外界留的门,具体的执行是在ApplicationContext的生命周期里。

经典实用场景,BeanDefinition属性值变量的替换

对BeanDefinition属性值进行修改,不管哪里注册的,都会走这里

经典常用的:

PropertySourcesPlaceholderConfigurer

BeanDefinition里面如下属性值变量的替换都在这里执行(@Autowired和@Value里的变量并不在这进行替换 、SpEL也不在此处处理)

替换BeanDefinition属性值的范围和顺序如下:

parentName

beanClassName

factoryBeanName

factoryMethodName

scope

propertyValues

constructorArgumentValues

Bean的生命周期

=========

实在是编不下去了,这个用做菜来举例的话,我头发要白一大片。这里我们就不以做菜举例了,只能以类的创建来举例了

正常创建类的流程:

(1)MovieListener listener = new MovieListener();

MovieFinder finder = new ColonDelimitedMovieFinder(“movies1.txt”);

(2)listener.setFinder(finder);

listener.setStartTime(new Date());

(3)listener.init();

对应上面三个步骤,我们分为三个方法:

1、实例化

2、populateBean属性赋值(@Autowired的属性依赖注入都是在这里处理)

3、初始化(属性赋值完后,我们做好准备工作对外开始服务)

所以spring为了让我们参与到bean的实例化与初始化过程,特意给我们留了口

为什么要划分出多一个第二步populateBean方法呢,拆分的更细其实也是有益处的,例如spring cloud的结合@RefreshScope和@ConfigurationProperties使用的bean,就用到了bean生命周期中的destroy和initializeBean 初始化的方法,跳过了实例化和属性赋值,直接去触发

ConfigurationPropertiesBindingPostProcessor进行@ConfigurationProperties注解类的属性值的绑定(这里的属性赋值并不是@Autowired @Value这样的属性赋值,而是@ConfigurationProperties(prefix = “xxx”)注解类对应的属性);因为是再次第三步初始化的initializeBean,所以第二步依赖注入的属性不会被改变,节省了成本

BeanPostProcessor

=================

在bean的生命周期中,我们能参与到哪些环节呢,spring给我们的最主要的还是通过三类BeanPostProcessor去参与进去。

BeanPostProcessor的类的继承关系

Spring IoC Container 原理解析

典型常用的BeanPostProcessor如下:

CommonAnnotationBeanPostProcessor

spring中最重要的BeanPostProcessor之一

@Resource

注解属性的赋值,找到对应的bean进行属性赋值

@WebServiceRef

不常用,不解释

继承自

InitDestroyAnnotationBeanPostProcessor又包含如下两个注解的处理

@PostConstruct

执行该注解对应的方法,在何时执行请看“虚拟世界”的图例

@PreDestroy

销毁时执行改注解方法,我们要搞清楚如何出生的,再去想如何没的,这里不做解释。

AutowiredAnnotationBeanPostProcessor

Spring boot中最重要的BeanPostProcessor 没有之一

@Autowired

常见问题:

为什么spring bean 一级缓存里没有 ResourceLoader、ApplicationContext、ApplicationEventPublisher、BeanFactory相关的bean,@Autowired为什么能注入对象进去呢?

也是这里进行了代码相关的类型判断,如果是上面4种类型的,直接找到对应的对象赋值了。

@Value

${xx} #{xx} 占位符的区别是什么 就是普通属性替换和SpEL的执行

@Qualifier

需配合@Autowired使用,@Autowired在找相关的bean时,也会按@Qualifier指定的bean name去查找。

ConfigurationPropertiesBindingPostProcessor

Spring boot中重要的BeanPostProcessor

@ConfigurationProperties注解类的处理

AnnotationAwareAspectJAutoProxyCreator

AOP里用到,Spring AOP 最重要的BeanPostProcessor没有之一

@Aspect的处理,将aop扫描到的方法类进行生成aop代理,这里我们也不做过多的解释,属于AOP的内容。

下面的章节我们将正式进入bean的生命周期,这里再回顾一下我们的虚拟世界

Spring IoC Container 原理解析

getMergeBeanDefinition

======================

合并BeanDefinition

为什么要合并BeanDefinition,我们这里用词还是跟spring源码里的方法名保持了一致,是为了方便大家看源码时能更好去对应上。

因为java面向对象设计的概念,类是可以继承的

如下这种xml声明方式,parent就有用,生成bean时会将parent bean的属性也进行注入,这样就能使用到父类的属性和方法。

Java config基于@Component注解时基本用不上了,因为生成的都不是ChildBeanDefinition

怎么合并,去看一下AbstractBeanDefinition的构造函数就知道各种其他类型的BeanDefinition如何转换为RootBeanDefinition,我们这里就不贴源码了。

Instantiation 实例化

=================

什么叫实例化 new MovieListener() 这样吗

涉及到static 方法块是否需要被执行,以及构造函数是否需要被执行,spring默认都是会执行到

postProcessBeforeInstantiation

==============================

InstantiationAwareBeanPostProcessor触发

这里可以干些什么,有什么使用场景,如果在这里有返回对象,则会直接跳到

BeanPostProcessor.postProcessAfterInitialization方法去,等于是直接跳到生命周期的末尾,期间的生命周期都不会执行

createBeanInstance

==================

这里呢,有什么场景暂时没发现,不过spring也给我们参与的机会=>BeanDefinition里的instanceSuplier

postProcessMergedBeanDefinition

===============================

MergedBeanDefinitionPostProcessor触发

这里可以干些什么,有什么使用场景,spring为什么要给我们留这个口?

BeanDefinitionRegistryPostProcessor注册BeanDefinition可以是任意类型,但是在bean的生命周期里(实例化之前),都会转变为RootBeanDefinition;所以这里spring给我们留了一个口,让我们还去访问RootBeanDefinition,可以用于获取信息和修改BeanDefinition信息;

首先搞清楚什么是:merged bean definition

Return a RootBeanDefinition for the given bean, by merging with the

parent if the given bean’s definition is a child bean definition.

在BeanDefinition生成的时候就已经merge过了,不管如何,实例化之前会拿到mergedBeanDefinition(实际是RootBeanDefinition类型)

**既然可以用于修改BeanDefinition,为什么该后置处理不在对象实例化之前给我们去调用呢?**如果是修改BeanDefinition,那么其实是跟BeanFactoryPostProcessor去修改BeanDefinition是有歧义的。如果想要修改Bean的实例化的类,还是得去BeanFactoryPostProcessor,这里只能影响实例化之后的生命周期。

这里其实就是给最后一次机会,能够去修改BeanDefinition(注意这里bean已经实例化了)

AutowiredAnnotationBeanPostProcessor 和

CommonAnnotationBeanPostProcessor

在这里

postProcessMergedBeanDefinition 就是去提前缓存了每个类的 @Autowired、@Value等注解属性信息,后面postProcessProperties直接使用而已。 不到这里加缓存后面再去取也可以

到这里我们主要分析了

applyMergedBeanDefinitionPostProcessors这段代码的作用,它的执行时机是在创建对象之后,属性注入之前。按照官方的定义来说,到这里我们仍然可以使用这个方法来修改bd的定义,那么相对于通过BeanFactoryPostProcessor的方式修改bd,applyMergedBeanDefinitionPostProcessors这个方法影响的范围更小,BeanFactoryPostProcessor影响的是整个Bean的生命周期,而applyMergedBeanDefinitionPostProcessors只会影响属性注入之后的生命周期。

polulateBean 属性赋值

=================

为什么属性赋值要单独拿出来,其实是属于初始化里面的吗;在spring里还真不是,不过要注意的是spring cloud的@RefreshScope是直接调用了destroy方法之后直接调用初始化方法,跳过了属性赋值,其实也就是跳过了@Autowired @Value等的属性赋值处理保留原有的。

postProcessProperties

=====================

InstantiationAwareBeanPostProcessor触发

给bean的属性赋值

AutowiredAnnotationBeanPostProcessor 和

CommonAnnotationBeanPostProcessor

就是在此处分别给@Autowired @Value、@Resource属性通过反射赋值

postProcessPropertiesValues(Deprecated)

=======================================

InstantiationAwareBeanPostProcessor触发

目前已经作废,被上面postProcessProperties方法替代

applyPropertyValues

===================

BeanDefinition里propertyValues的SpEL的处理在这里,通过java config配置的类基本上已经用不到这里了

Initialization 初始化

==================

什么叫初始化,简单点说就是执行类的各种方法

各类Aware接口方法

===========

用于接收各类的spring对象

postProcessBeforeInitialization

===============================

由BeanPostProcessor触发

CommonAnnotationBeanPostProcessor

@PostConstruct注解的方法在此处调用执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值