Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

参考了Spring 官网文档
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html
一个IOC讲得很好的博客
https://blog.csdn.net/ivan820819/article/details/79744797

之前总结的Spring文章比较水,这次好好来
文章需要有些Spring源码基础(可以看我的水文)

系列文章目录和关于我

一丶什么是 IOC 和DI

IoC也被称为依赖注入DI,对象在被构造方法构造,或者工厂方法创造返回,仅通过构造函数参数、工厂方法的参数,或者对象设置的属性来定义他们的关系(即与它们一起工作的其他对象)。

  • 什么叫依赖——对象A需要对象B一起完成工作,这种关系叫做依赖
  • IoC是如何描述依赖的
  • 构造方法的参数
  • 产生对象的工厂方法的参数
  • 对象设置的属性

IoC容器在bean被创造后将注入这些依赖,从根本上说这个过程就叫做反转(因此得名控制反转)

IoC理论出现之前,我们定义的每一个对象之间的关系是这样的,这里面齿轮之间的咬合象征着 "依赖",ABCD四个对象都依赖与彼此,耦合度很高。

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

IoC理论出现后,多了一个中间件——IoC容器(万能的解耦方案,耦合度高了就加一层)

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

IoC容器的好处在于,ABCD四个对象并不是直接依赖的,没有了直接的依赖关系,齿轮的传动交给了IoC容器,IoC容器获得了控制权,控制权从对象本身交给了IoC容器,IoC容器如同一个粘合剂。

对于传统的方式,我们在实例化A的时候一定要在构造方法或者其他地方,让A实例化B并且持有B的引用,这就好比对象A控制了获取对象B的过程。但是引入了IoC之后,IoC容器负责在实例化A之后为A 注入对象B(或者在构造对象A的时候,将B作为构造方法的参数,工厂方法的参数)对象A从主动获取对象B,变成了IoC容器控制对象A获取对象B——这就叫做控制反转。

DI(依赖注入)是实现IoC的一种方式——由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

二丶Spring Bean ,BeanDefinition,BeanDefinitionReader,BeanDefinitionRegistry

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

1.什么是spring bean

Spring Bean是指Spring 容器管理的对象,一个Spring 容器管理多个Spring bean,对它们进行实例化,依赖注入,初始化等。这些 bean 是使用我们提供给spring容器的配置元数据创建的(例如,以 XML <bean></bean>定义的形式)。

在容器中,这些 bean 定义表示为 BeanDefinition 对象,其中包含以下元数据:

  • 一个包限定的类名:通常是被定义的 bean 的全限定类名,实际实现类。
  • Bean 行为配置元素,它说明 bean 在容器中的行为方式(作用域、生命周期回调等)。
  • 当前bean 依赖的其他bean。
  • 等等

2.BeanDefinition

BeanDefinition 描述了一个 bean 实例,它记录了bean的属性值、构造函数参数值以及其他更多信息。 BeanDefinition在Spring 管理bean中至关重要,指导了Spring 依据 BeanDefinition生成Bean,bean的作用域,是否懒加载等等。

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

BeanDefinition中具有设置和获取 &#x6B64;bean &#x5B9A;&#x4E49;&#x7684;&#x7236;BeanDefinition&#x7684;&#x540D;&#x79F0;&#xFF08;&#x5982;&#x679C;&#x6709;&#xFF09;bean &#x7C7B;&#x540D;, Bean&#x7684;&#x4F5C;&#x7528;&#x57DF;Bean&#x662F;&#x5426;&#x61D2;&#x52A0;&#x8F7D;&#x5F53;&#x524D;bean&#x4F9D;&#x8D56;&#x7684;bean&#x540D;&#x79F0;&#x662F;&#x5426;Autowire&#x5019;&#x9009;&#x8005;&#x662F;&#x5426;&#x662F;&#x6700;&#x4E3B;&#x8981;&#x7684;&#x81EA;&#x52A8;&#x88C5;&#x914D;&#x5019;&#x9009;&#x8005;&#x521D;&#x59CB;&#x5316;&#x65B9;&#x6CD5;&#x540D;&#x79F0;&#x9500;&#x6BC1;&#x65B9;&#x6CD5;&#x540D;&#x79F0;&#x662F;&#x5426;&#x5355;&#x4F8B;&#x662F;&#x5426;&#x539F;&#x578B;bean&#x5C5E;&#x6027;&#x503C;

传统的基于XML Spring 容器便是使用对应的 BeanDefinitionReader解析XML将xml中的信息包装成 BeanDefinition保存到Spring容器中,后续由Spring容器根据 BeanDefinition对Bean进行管理。

3.BeanDefinitionReader

Bean定义信息读取器,定义了如下方法

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

BeanDefinitionReader的典型实现莫过于 XmlBeanDefinitionReader,它负责解析xml生成BeanDefinition并注册(spring源码学习笔记1——解析xml生成BeanDefinition的过程解析

这个类关系图中有两个异类 AnnotatedBeanDefinitionReader, ClassPathBeanDefinitionScanner,它们没有实现 BeanDefinitionReader但是存在的目的和 BeanDefinitionReader是一致的——将生成BeanDefinition并注册到容器,并且根据配置生成beanDefinition的动作交给他们,并不是直接让BeanFactory来完成,更加可扩展,更加单一职责。

4.BeanDefinitionRegistry

Bean定义注册中心,主要是对 BeanDefinition的增删改查,自然内部会对 BeanDefinition信息进行存储。

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

DefaultListableBeanFactory是一个Bean工厂,Spring中很多上下文都是通过组合它来实现对Bean的管理。其中还涉及到 AliasRegistry顾名思义就是对bean的别名进行管理。

三丶BeanFactory类结构体系

Spring 容器的根接口,主要提供了 getBean(根据bean名称,类型等获取bean的方法),以及判断bean是否单例,是否原型等方法。Spring建议 BeanFactory的实现类尽可能的支持bean的生命周期接口的回调(比如 InitializingBean#afterPropertiesSet等)其中最关键的实现类莫过于 DefaultListableBeanFactory

1.从DefaultListableBeanFactory看BeanFactory类结构体系

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
  • HierarchicalBeanFactory层次结构的 BeanFactory提供两个方法 getParentBeanFactory获取当前 BeanFactory的父工厂, containsLocalBean当前 BeanFactory是否包含指定名称的bean
  • ListableBeanFactory可罗列的 BeanFactory,这里的可罗列意味着此 BeanFactory提供类似于 <t> Map<string, t> getBeansOfType(@Nullable Class<t> type)</t></string,></t>这种获取满足条件的一系列bean的功能
  • AutowireCapableBeanFactory具备自动装备功能的 BeanFactory,提供了 createBean&#x5B9E;&#x4F8B;&#x5316;&#xFF0C;&#x5C5E;&#x6027;&#x586B;&#x5145;&#xFF0C;&#x56DE;&#x8C03;&#x751F;&#x547D;&#x5468;&#x671F;&#x7684;&#x521B;&#x5EFA;bean, autowire&#x81EA;&#x52A8;&#x88C5;&#x914D;bean, initializeBean &#x56DE;&#x8C03;&#x76F8;&#x5173;&#x521D;&#x59CB;&#x5316;&#x65B9;&#x6CD5;,等方法
  • ConfigurableBeanFactory 可配置的 BeanFactory,提供了 setParentBeanFactorysetBeanClassLoader, addBeanPostProcessor等配置bean工厂的方法
  • ConfigurableListableBeanFactory,实现了 ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory,具备其他三者的功能的同时,还提供了 ignoreDependencyType &#x5FFD;&#x7565;&#x7ED9;&#x5B9A;&#x4F9D;&#x8D56;&#x7C7B;&#x578B;&#x7684;&#x81EA;&#x52A8;&#x88C5;&#x914D;registerResolvableDependency &#x6CE8;&#x518C;&#x6307;&#x5B9A;&#x7C7B;&#x578B;&#x7684;&#x4F9D;&#x8D56;&#x4F7F;&#x7528;&#x6307;&#x5B9A;&#x7684;&#x5BF9;&#x8C61;&#x8FDB;&#x884C;&#x6CE8;&#x5165;等功能

2.从DefaultListableBeanFactory 看注册系接口

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
  • AliasRegistry:别名注册, SimpleAliasRegistry是主要的实现,内部使用一个 ConcurrentHashMap存储bean名称和别名
  • BeanDefinitionRegistry Bean定义注册中心,主要是对 BeanDefinition的增删改查
  • SingletonBeanRegistry 单例bean注册,提供注册单例,获取单例,等方法

四丶ApplicationContext类结构体系

1.ApplicationContext类结构体系分析

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

从类图我们可以看到 BeanFactoryApplicationContext的区别,总体来说 ApplciationContext是一个 BeanFactory但是包含其他更多的功能,这些功能就在它实现的其他接口体现

  • EnvironmentCapable提供获取 Environment的能力
  • ResourceLoader:用于加载资源(例如类路径或文件系统资源)的策略接口,根据路径获取资源包装成 Resource
  • ResourcePatternResolverResourceLoader的子接口,提供根据路径匹配获取资源的能力
  • ApplicationEventPublisher 事件发送接口
  • MessageSource:用于解析消息的策略接口,用于实现国际化

2.ClassPathXmlApplicationContext类结构体系分析

基于类路径下xml文件的Spring应用程序上下文,通过解析类路径下的xml来加载Spring容器

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
  • ConfigurableApplicationContext可拱配置的Spring容器上下文,支持添加事件监听器,设置父容器,设置环境,设置后置处理器等操作
  • AbstractApplicationContext 通过组合的方式,实现容器上下文的功能。提供了诸多模板方法,并且定义了Spring容器刷新的基本逻辑,其中定义了 refreshBeanFactory在spring容器刷新的时候触发 BeanFactory的刷新
  • AbstractRefreshableApplicationContext实现了 refreshBeanFactory定义了刷新 BeanFactory的流程——创建 BeanFactory,加载 BeanDefinition(抽象方法交给子类实现)
  • AbstractRefreshableConfigApplicationContext实现了 InitializingBeanafterPropertiesSet方法中调用容器刷新的 refresh方法
  • AbstractXmlApplicationContext抽象的xml上下文,对从xml加载 BeanDefinition进行了实现,提供了 getConfigResources方法让子类自定义xml文件的来源

3.AnnotationConfigApplicationContext类结构体系分析

基于注解包路径扫描的容器上下文,内部持有 AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner来完成 BeanDefinition的注册

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
  • GenericApplicationContext 内部持有一个 DefaultListableBeanFactory,并且继承了 BeanDefinitionRegistry提供注册 BeanDefinition的方法,但是 refresh方法不会去加载资源下的 BeanDefinition,不像 ClassPathXmlApplicationContext一样会根据路径加载 BeanDefinition
  • AnnotationConfigRegistry,提供 register&#xFF08;&#x6CE8;&#x518C;&#x4E00;&#x4E2A;&#x6216;&#x591A;&#x4E2A;&#x8981;&#x5904;&#x7406;&#x7684;&#x6CE8;&#x89E3;&#x7C7B;&#xFF09;scan&#xFF08;&#x5728;&#x6307;&#x5B9A;&#x5305;&#x8DEF;&#x5F84;&#x4E2D;&#x6267;&#x884C;&#x626B;&#x63CF;&#xFF09;方法

五丶ApplicationContext#refresh

ApplicationContext#refresh方法是Spring源码学习中最重要的方法,是Spring容器启动会执行的方法,涉及到BeanDefinition的扫描,单例bean的生成等等。下面我们从 AbstractApplicationContextrefresh方法简单分析下,Spring容器启动到底做了些什么

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

1.刷新BeanFactory

这部分会调用 refreshBeanFactory(抽象方法交由子类实现),实现对BeanFactory的刷新,对于 AbstractRefreshableApplicationContext的子类会在其中销毁原有的BeanFactory然后重写创建BeanFactory,对于 GenericApplicationContext子类什么都不会做。

体现在 ClassPathXmlApplicationContext会根据配置的xml路径重新解析xml生成BeanDefinition并注册,对于 AnnotationConfigApplicationContext则是什么都不做。

1.1 AbstractRefreshableApplicationContext#refreshBeanFactory 加载BeanDefinition

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

loadBeanDefinitions是一个抽象方法,具体如何加载 BeanDefinition交给子类去实现, ClassPathXmlApplication加载BeanDefinition的流程在其父类 AbstractXmlApplicationContext中内部使用 XmlBeanDefinitionReader#reader方法读取 Resouce生成BeanDefinition

1.2GenericApplicationContext的子类是如何加载BeanDefinition的

AnnotationConfigApplicationContext为例

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

其构造方法,如果传入的是一个包路径,那么会调用无参构造方法,从而new 出 AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner,然后使用 ClassPathBeanDefinitionScanner扫描包下的所有具备 @Component注解(包括复合注解)的类,如果传入的是若干个类那么 AnnotatedBeanDefinitionReader会对这些类进行注册。

2.prepareBeanFactory前缀准备

这部分主要是对 ConfigurableListableBeanFactory进行一些设置。其中会加入一个 ApplicationContextAwareProcessorApplicationListenerDetectorBeanPostProcessor,并且忽略 EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAwareMessageSourceAware, ApplicationContextAware等接口自动装配,并且注册 BeanFactory, ResourceLoader, ApplicationEventPublisher, ApplicationContext的自动装配值(依赖注入的时候,会使用注册的值进行设置)

3.postProcessBeanFactory

留给子类扩展的方法,对于web应用上下文会在其中设置 ServletContextAwareProcessorBeanPostProcessor,并且注册request和 session的scope

4.invokeBeanFactoryPostProcessors 调用BeanFactoryPostProcessor

此方法会对 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor中的方法进行调用。调用通过 ConfigurableApplicationContext#addBeanFactoryPostProcessor添加的,或者 BeanFactoryBeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor类型的bean的bean名称, getBean方法实例化后调用

4.1 什么是BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor

  • BeanFactoryPostProcessor:Spring留给我们的一个扩展接口,在 BeanDefinition加载注册完之后,并执行一些前置操作之后会实例化所有的 BeanFactoryPostProcessor实例并且回调对应 postProcessBeanFactory方法。允许自定义修改应用程序上下文的 bean 定义,调整上下文底层 bean 工厂的 bean 属性值。应用程序上下文可以在其 bean 定义中自动检测 BeanFactoryPostProcessor bean,并在创建任何其他 bean 之前应用它们。
  • BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的子类,新增 postProcessBeanDefinitionRegistry方法,在检测`BeanFactoryPostProcessor类型的BeanDefinition之前就会调用所有BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry,这个方法允许我们新增,修改,删除,查找之前注册的BeanDefinition,所有可以在这个方法中对BeanFactoryPostProcessor进行调整,也可以对其他所有BeanDefinition进行调整

4.2 重要的BeanFactoryPostProcessor

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
4.2.1 PropertyPlaceholderConfigurer

它根据本地属性,系统属性和环境变量解析 ${...} 占位符,会替换掉 BeanDefinition中的占位符。这也是基于xml配置数据源的时候可以把数据库配置放在一个文件中,然后通过占位符进行引用

4.2.2 EventListenerMethodProcessor

postProcessBeanFactory会实例化 EventListenerFactory并且持有,并且它继承了 SmartInitializingSingletonafterSingletonsInstantiated方法中,会把每一个在方法中标注了 @EventListener(或其复合注解)的bean和方法包装成 ApplicationListener注册到Spring上下文(其实是委托给对于的事件多播器 ApplicationEventMulticaster

&#x4E3A;&#x5565;@Aysnc&#x6CE8;&#x89E3;&#x53EF;&#x4EE5;&#x642D;&#x914D;@EventListener&#x5B9E;&#x73B0;&#x5F02;&#x6B65;&#x7684;&#x6548;&#x679C;
afterSingletonsInstantiated&#x8C03;&#x7528;&#x5B9E;&#x9645;&#x662F;&#x6240;&#x6709;&#x5355;&#x4F8B;bean&#x521D;&#x59CB;&#x5316;&#x540E;
&#x8FD9;&#x65F6;&#x5019;bean&#x5DF2;&#x8FD1;&#x662F;&#x88AB;@Aysnc&#x5BF9;&#x4E8E;&#x7684;BeanPostProcessor&#x8FDB;&#x884C;CGLIB&#x589E;&#x5F3A;&#x7684;bean&#x4E86;
&#x8C03;&#x7528;&#x65B9;&#x6CD5;&#x4FBF;&#x4EE5;&#x53CA;&#x662F;&#x5F02;&#x6B65;&#x8C03;&#x7528;&#x7684;&#x4E86;

&#x5176;&#x5B9E;spring&#x7684;&#x9ED8;&#x8BA4;&#x7684;&#x591A;&#x64AD;&#x5668;SimpleApplicationEventMulticaster,&#x5185;&#x90E8;&#x6301;&#x6709;&#x4E00;&#x4E2A;JUC&#x7684;Executor&#xFF0C;&#x53EF;&#x4EE5;&#x914D;&#x7F6E;&#x6210;&#x7EBF;&#x7A0B;&#x6C60;&#xFF0C;&#x90A3;&#x4E48;&#x5C31;&#x662F;&#x4E0D;&#x9700;&#x8981;@Aysnc&#x4E5F;&#x80FD;&#x5F02;&#x6B65;&#x8C03;&#x7528;
4.2.3 ConfigurationClassPostProcessor

解析加了 @Configuration的配置类,还会解析 @ComponentScan@ComponentScans注解扫描的包,以及解析 @Bean&#xFF0C;@Import,@PropertySources,@ImportResource等注解,将这些注解信息解析成 BeanDefinition注册到Spring BeanFactory中。

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
4.2.4 工作中碰到的用法

其实和 PropertyPlaceholderConfigurer差不多,公司为了避免配置文件中明文存储数据库密码,采用一种加密方式配置文件存储加密后的密文,然后用SpringBoot的自动配置注入一个BeanFactoryPostProcessor进行解密。

5.registerBeanPostProcessors 注册BeanPostProcessor

5.1 什么是BeanPostProcessor

一个允许自定义修改新 bean 实例的接口,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的

5.2 registerBeanPostProcessors的逻辑

获取BeanFactory中的BeanPostProcessor类型的bean,根据 &#x5B9E;&#x73B0;PriorityOrdered&#x4E2D;&#x7684;getOrder&#x65B9;&#x6CD5;&#x987A;&#x5E8F;> &#x5B9E;&#x73B0;Ordered&#x4E2D;getOrder&#x65B9;&#x6CD5;&#x7684;&#x987A;&#x5E8F;> @Order&#x6807;&#x6CE8;&#x7684;&#x987A;&#x5E8F;> &#x6CA1;&#x6709;&#x5B9E;&#x73B0;&#x8FD9;&#x4E24;&#x4E2A;&#x63A5;&#x53E3;&#x4E5F;&#x6CA1;&#x6709;&#x6807;&#x6CE8;&#x6CE8;&#x89E3;&#x7684;&#x987A;&#x5E8F;(是否支持 @Order注解排序,取决于BeanFactory使用的比较器)

5.3 BeanPostProcessor 类结构体系

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
5.3.1 BeanPostProcessor

提供两个方法: postProcessBeforeInitialization(&#x5728;bean&#x521D;&#x59CB;&#x5316;&#x65B9;&#x6CD5;&#x8C03;&#x7528;&#x4E4B;&#x524D;&#x88AB;Spring&#x5BB9;&#x5668;&#x8C03;&#x7528;), postProcessAfterInitialization&#xFF08;&#x5728;bean&#x521D;&#x59CB;&#x5316;&#x65B9;&#x6CD5;&#x8C03;&#x7528;&#x4E4B;&#x540E;&#x8C03;&#x7528;&#xFF09;

5.3.2 MergedBeanDefinitionPostProcessor

在BeanPostProcessor的基础上新增一个方法 postProcessMergedBeanDefinition在创建bean时,会先获取bean对应的BeanDefinition(Spring可能对存在父子关系的beanDefinition进行合并)后,spring会实例化bean然后会调用 postProcessMergedBeanDefinition,入参中有 BeanDefinition可以进行自定义的修改

5.3.3 InstantiationAwareBeanPostProcessor

在BeanFactoryPostProcessor的基础新增 postProcessBeforeInstantiation(&#x5728;Spring&#x5B9E;&#x4F8B;&#x5316;bean&#x4E4B;&#x524D;&#x8C03;&#x7528;&#xFF0C;&#x8FD4;&#x56DE;&#x975E;&#x7A7A;&#x5BF9;&#x8C61;&#x53EF;&#x4EE5;&#x963B;&#x65AD;Spring&#x540E;&#x7EED;&#x5B9E;&#x4F8B;&#x5316;&#xFF0C;&#x5C5E;&#x6027;&#x586B;&#x5145;&#xFF0C;&#x521D;&#x59CB;&#x5316;&#x65B9;&#x6CD5;&#x7684;&#x8C03;&#x7528;&#x54AF;&#x6D41;&#x7A0B;), postProcessAfterInstantiation&#xFF08;&#x5728;&#x5B9E;&#x4F8B;&#x5316; bean &#x4E4B;&#x540E;&#xFF0C;&#x4F46;&#x5728; Spring &#x5C5E;&#x6027;&#x586B;&#x5145;&#x53D1;&#x751F;&#x6267;&#x884C;&#x64CD;&#x4F5C;&#xFF09;, postProcessProperties&#x5728;spring&#x5C06;&#x7ED9;&#x5B9A;&#x7684;&#x5C5E;&#x6027;&#x503C;&#x5E94;&#x7528;&#x5230;&#x7ED9;&#x5B9A;&#x7684; bean &#x540E;&#x8C03;&#x7528;

5.3.4 DestructionAwareBeanPostProcessor

在BeanFactoryPostProcessor的基础新增 postProcessBeforeDestruction&#x5728;bean&#x88AB;&#x9500;&#x6BC1;&#x4E4B;&#x524D;&#x8C03;&#x7528;

5.3.5 SmartInstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor的基础新增 determineCandidateConstructors(Spring&#x4F1A;&#x63A8;&#x65AD;&#x6784;&#x9020;&#x65B9;&#x6CD5;&#x6765;&#x53CD;&#x5C04;&#x751F;&#x6210;&#x5BF9;&#x8C61;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x53EF;&#x4EE5;&#x51B3;&#x5B9A;&#x4F7F;&#x7528;&#x54EA;&#x4E9B;&#x6784;&#x9020;&#x65B9;&#x6CD5;)getEarlyBeanReference(&#x83B7;&#x53D6;&#x5BF9;&#x6307;&#x5B9A; bean &#x7684;&#x65E9;&#x671F;&#x66B4;&#x9732;&#x7684;&#x5F15;&#x7528;,&#x5982;&#x679C;&#x51FA;&#x73B0;&#x5FAA;&#x73AF;&#x4F9D;&#x8D56;&#xFF0C;&#x83B7;&#x53D6;&#x5BF9;&#x8C61;&#x7684;&#x65F6;&#x5019;&#x4F1A;&#x8C03;&#x7528;&#x6B64;)

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

5.4 Spring源码中BeanPostProcessor的应用

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
5.4.1 ApplicationContextAwareProcessor

负责 EnvironmentAware(&#x73AF;&#x5883;&#x611F;&#x77E5;&#x63A5;&#x53E3;), EmbeddedValueResolverAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x4E2D;&#x89E3;&#x6790;&#x5B57;&#x7B26;&#x4E32;&#x503C;&#x7684;&#x7B80;&#x5355;&#x7B56;&#x7565;&#x63A5;&#x53E3;&#x5B9E;&#x73B0;)ResourceLoaderAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x4E2D;&#x7528;&#x4E8E;&#x52A0;&#x8F7D;&#x8D44;&#x6E90;&#xFF08;&#x4F8B;&#x5982;&#x7C7B;&#x8DEF;&#x5F84;&#x6216;&#x6587;&#x4EF6;&#x7CFB;&#x7EDF;&#x8D44;&#x6E90;&#xFF09;&#x7684;&#x7B56;&#x7565;&#x63A5;&#x53E3;&#x5B9E;&#x73B0;)ApplicationEventPublisherAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x4E2D;&#x4E8B;&#x4EF6;&#x53D1;&#x5E03;&#x529F;&#x80FD;&#x7684;&#x63A5;&#x53E3;&#x5B9E;&#x73B0;)MessageSourceAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x89E3;&#x6790;&#x6D88;&#x606F;&#x7684;&#x7B56;&#x7565;&#x63A5;&#x53E3;&#x7684;&#x5B9E;&#x73B0;)ApplicationContextAware(spring&#x4E0A;&#x4E0B;&#x6587;&#x611F;&#x77E5;&#x63A5;&#x53E3;)接口的回调,回调对于的set方法

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
5.4.2 AnnotationAwareAspectJAutoProxyCreator

Spring 源码学习笔记10——Spring AOP提到过,AnnotationAwareAspectJAutoProxyCreator负责解析AspeJ注解标注类,排序然后包装成 Advisor,最后对判断bean是否需要代理,最后由ProxyFactory获取AopProxy进行JDK动态代理或者CGLIB动态代理,生成代理对象,这就是Spring 基于注解的AOP原理

5.4.3 AutowiredAnnotationBeanPostProcessor

Spring源码学习笔记7——Spring bean的初始化,和 Spring源码学习笔记9——构造器注入及其循环依赖 中学过,其 determineCandidateConstructors会根据 @Autowired or @Value推断构造方法,如果只有一个构造函数那么模式使用此,这也就是为什么,提供一个构造函数,spring会从容器中拿到复合参数类型bean进行构造,也是为什么 @Autowired or @Value标注在构造方法会生效。其 postProcessProperties会进行属性注入(利用字段反射,或者set方法反射),其 postProcessMergedBeanDefinition方法先于另外两个方法执行,它会扫描bean class中的所有方法和字段,如果具备 @Autowired or @Value注解 那么会包装成 InjectionMetadata并缓存,后续在 determineCandidateConstructorspostProcessProperties中发挥作用

5.4.4 CommonAnnotationBeanPostProcessor

Spring源码学习笔记7——Spring bean的初始化 学习过,负责解析 @PostConstruct, @PreDestroy, @Resource,在 postProcessMergedBeanDefinition中会把 @PostConstruct, @PreDestroy标注的方法包装成 LifecycleMetadata,其中 PostConstruct标注的放法会在 postProcessBeforeInitialization&#xFF08;&#x5B9E;&#x4F8B;&#x5316;&#x4E4B;&#x540E;&#xFF0C;&#x521D;&#x59CB;&#x5316;&#x4E4B;&#x524D;&#xFF09;中被调用, PreDestroy标注的方法在 postProcessBeforeDestruction bean被消耗之前调用。 @Resource@Autowired类似,都是在 postProcessProperties中调用,但是获取bean的策略有所不同,可以看Spring源码学习笔记7——Spring bean的初始化中对二者进行的对比

5.4.5 ApplicationListenerDetector

ApplicationListenerDetector 监听器探测器,它会在ApplicationListener类型的bean被实例化之后,注册到上下文的事件多播器中。在ApplicationListener类型的bean被销毁之前,从上下文持有的事件多播器中删除

5.4.6 AsyncAnnotationBeanPostProcessor

使用 AsyncAnnotationAdvisor对bean进行增强,如果方法上具备 @Async注解,会调用 AnnotationAsyncExecutionInterceptor中的 invoke进行增强,实现异步调用,也就是基于Spring AOP的实现。

5.4.7 ScheduledAnnotationBeanPostProcessor

会扫描每一个bean的方法,如果上面标注了 @Scheduled, @Schedules注解那么会被注册到 TaskScheduler,基于Juc中的定时任务线程池原理定时执行。

6.initApplicationEventMulticaster 初始化事件多播器

会从容器中,获取名称为 applicationEventMulticaster的bean,如果存在那么Spring容器将持有此事件多播器,监听器的注册,取消注册,事件的推送都依赖此事件多播器,如果没有对应的bean那么使用默认的 SimpleApplicationEventMulticaster

SimpleApplicationEventMulticaster:如果配置了 Executor那么响应事件会调用 Executor#execute具体异步还是同步,取决于 Executor的内部实现(这就是JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析中提到的Executor的作用——把任务提交与每个任务将如何运行的机制进行解耦),如果没有那么就由发送事件的线程进行调用(同步)

7.onRefresh钩子方法

SpringBoot使用的 AnnotationConfigServletWebServerApplicationContext在这个方法里面开启Tomcate服务器

8.registerListeners注册监听器

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

负责把事件监听器 注册到多播器中,并且在事件多播器初始化执行之前,可能存在一些事件没有处理,这些事件都会放在earlyApplicationEvents集合中,在多播器初始化后,会把earlyApplicationEvents置为null 以后的事件都是直接委托给多播器进行推送。

9.finishBeanFactoryInitialization实例化所有非懒加载的单例bean

这个方法贯穿了bean的实例化,属性填充,初始化。

Spring源码学习笔记6——Spring bean的实例化

Spring源码学习笔记7——Spring bean的初始化

Spring源码学习笔记8——Spring是如何解决循环依赖的

Spring源码学习笔记9——构造器注入及其循环依赖

这四篇笔记中详细的说明了Bean的初始化流程,下面我进行粗略的总结,提前初始化单例bean的方法是 DefaultListableBeanFactory#preInstantiateSingletons

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

DefaultListableBeanFactory#preInstantiateSingletons存在两个for循环,第一个是实例化加载所有的单例非懒加载bean,第二个for循环是在加载完后,调用实现了 SmartInitializingSingleton接口bean的 afterSingletonsInstantiated方法,这是spring留给我们的一个扩展接口

9.1.什么样的bean才会被实例化

首先要满足 !bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit(),即不是抽象,且单例,且不是懒加载的 BeanDefinition

9.2 FactoryBean和普通bean的不同处理

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

9.3 Spring创建bean

上面我们看到初始化所有懒加载单例bean调用的是 BeanFactory#getBean(beanName),这里的BeanFactory一般是 DefaultSingletonBeanRegistry其内部使用map组成三级缓存,并且还要对factoryBan的缓存,如下图

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

下面我们看下创建bean的逻辑

9.3.1前置逻辑 factoryBean和父beanFactory相关

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

首先是一级缓存即单例池中获取,如果之前之前创建过单例对象,那么会被缓存到一级缓存单例池中,这时候就直接拿到了,但是拿到的可能是 FactoryBean,所有调用 getObjectForBeanInstance方法,如果是FactoryBean那么会调用其 getObject生成bean。如果当前BeanFactory没有此beanName对应的BeanDefinition那么会调用父beanFactroy的 getBean方法。反之说明存在对应的beanDefinition这时候就是取创建bean的流程了

9.3.2 实例化bean——createBeanInstance方法
9.3.2.1 实例化单例对象

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

创建bean之前,首先会获取当前beanDefinition中依赖的bean,这个可以通过 @DependOn注解或者xml标签指定,spring会先去加载这些bean(同样是使用getBean(bean名称)),然后再来实例化当前bean。

实例化之前首先会从一级缓存中拿,如果由那么直接返回,然后调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation如果返回了一个非null对象那么会调用 BeanPostProcessor#postProcessAfterInitialization然后返回,也就是说 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation允许我们阻断spring实例化,依赖注入,初始化bean的流程,使用这个接口产生的bean,如果产生了那么调用 BeanPostProcessor#postProcessAfterInitialization这意味着bean以及初始化完了(注意是初始化,也就是说明 postProcessBeforeInstantiation需要我们自己实例化对象,初始化对象。并且意味着SpringAop是继续生效的)。

其次我们可以通过在beanDefinition中指定 instanceSupplier来自定义spring bean,然后直接返回。或者如果我们指定了由工厂方法生成,那么会解析工厂方法入参,从容器中拿到对应的bean然后调用对应的工厂方法,生成对象,然后直接返回。这两种方式都不会让aop生效,因为 BeanPostProcessor没有被回调。

再者调用SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors,来决定使用哪个构造函数,如果存在优先选择public且参数最多的构造函数进行构造。这里就是 AutowiredAnnotationBeanPostProcessor怎么决定构造函数的,它会优先选择由 @Autowired or @Value注解的,如果只有一个那么直接使用唯一的一个构造函数,其余情况返回null,后续Spring自己使用构造函数,还是使用CGLIB生成子类的策略实例化bean。

9.3.2.2 实例化原型对象

创建原型对象和单例对象类似,但是原型对象是不允许循环依赖的,beanFactory使用 prototypesCurrentlyInCreationThreadLocal保存了原型对象是否处于创建中,如果发送循环依赖那么将抛出异常

9.3.2.3实例化特殊作用域的bean
&#x8FD9;&#x91CC;&#x8BF4;&#x662F;&#x5B9E;&#x4F8B;&#x5316;&#xFF0C;&#x5176;&#x5B9E;&#x662F;&#x5B9E;&#x4F8B;&#x5316;+&#x5C5E;&#x6027;&#x586B;&#x5145;+&#x521D;&#x59CB;&#x5316;
&#x4E4B;&#x6240;&#x4EE5;&#x8BF4;&#x5B9E;&#x4F8B;&#x5316;&#xFF0C;&#x662F;&#x56E0;&#x4E3A;&#x5355;&#x4F8B;&#xFF0C;&#x539F;&#x578B;&#xFF0C;&#x7279;&#x6B8A;&#x4F5C;&#x7528;&#x57DF;&#x7684;bean&#x53EA;&#x662F;&#x5B9E;&#x4F8B;&#x5316;&#x89E6;&#x53D1;&#x7684;&#x6761;&#x4EF6;&#x4E0D;&#x540C;
&#x5355;&#x4F8B;&#x53EA;&#x5B9E;&#x4F8B;&#x5316;&#x4E00;&#x6B21;
&#x539F;&#x578B;&#x6BCF;&#x6B21;getBean&#x90FD;&#x5B9E;&#x4F8B;&#x5316;
&#x7279;&#x6B8A;&#x4F5C;&#x7528;&#x57DF;&#x53D6;&#x51B3;&#x4E8E;&#x4F5C;&#x7528;&#x57DF;&#x7684;&#x903B;&#x8F91;

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

我们重点关注下 Scope#get方法,它是如何控制作用域的,此方法的含义是先尝试在Scope中拿(一般是一个缓存,Map或者ThreadLocal)如果没有那么调用后续传入的lambda。

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
  • SessionScope 和 RequestScope session 和request 范围 SessionScope 和 RequestScope 都是基于 RequestContextHolder(内部使用 requestAttributesHolder&#x7684;ThreadLocal存储请求信息,在 FrameworkServlet也就是 DispatcherServlet的父类中,每当一个请求访问时就把请求信息存储到ThreadLocal中,也就是说,session和request的作用域,必须要求请求时通过 DispatcherServlet的)实现的,不同的是 SessionScope#get会把 Session对象作为互斥锁(也许是因为同一个session可以并发发生请求,这时候需要获取互斥锁,避免相同session不同bean实例), RequestScope#get则不会,二者控制的bean实例都是存储在ThreadLocal中的 RequestAttributes对象中, RequestAttributes的子类 ServletRequestAttributes会根据Scope的不同选择把bean存在request中还是session中从而实现作用域的控制。
  • ServletContextScope

它是基于 servletContext实现的,一个应用只有一个 servletContext

  • SimpleThreadScope

它是基于 ThreadLocal实现的

  • SimpleTransactionScope

基于 TransactionSynchronizationManager实现的, TransactionSynchronizationManager内部基于ThreadLocal,和 SimpleThreadScope不同的是,Spring创建的逻辑事务,即使在同一线程上,如果是一个独立的事务,spring会先解绑当前线程上面的信息,挂起当前事务,从而导致两个逻辑事务使用到的bean是不同的bean

&#x4EC0;&#x4E48;&#x6837;&#x7684;&#xFF0C;&#x4E8B;&#x52A1;&#x88AB;&#x89C6;&#x4F5C;&#x65F6;&#x4E00;&#x4E2A;&#x72EC;&#x7ACB;&#x4E8B;&#x52A1;&#x6635;

&#x5982;&#x679C;&#x5916;&#x90E8;&#x4E0D;&#x5B58;&#x5728;&#x4E00;&#x4E2A;&#x4E8B;&#x52A1;&#xFF0C;&#x5E76;&#x4E14;&#x4F20;&#x64AD;&#x7EA7;&#x522B;&#x662F;REQUIRED,REQUIRES_NEW,NESTED
&#x5982;&#x679C;&#x5916;&#x90E8;&#x5B58;&#x5728;&#x4E00;&#x4E2A;&#x4E8B;&#x52A1;&#xFF0C;&#x4E14;&#x4F20;&#x64AD;&#x7EA7;&#x522B;&#x4E3A;REQUIRES_NEW
&#x5982;&#x679C;&#x5916;&#x90E8;&#x5B58;&#x5728;&#x4E00;&#x4E2A;&#x4E8B;&#x52A1;&#xFF0C;&#x4E14;&#x4F20;&#x64AD;&#x7EA7;&#x522B;&#x4E3A;&#x5D4C;&#x5957;&#x4E8B;&#x52A1;&#xFF0C;&#x4F46;&#x662F;&#x6B64;&#x65F6;&#x4E0D;&#x662F;&#x901A;&#x8FC7;&#x4FDD;&#x5B58;&#x70B9;&#x6765;&#x5B9E;&#x73B0;&#x5D4C;&#x5957;&#x4E8B;&#x52A1;

&#x4E0A;&#x9762;&#x4E09;&#x4E2A;&#x6761;&#x4EF6;&#x4E5F;&#x610F;&#x5473;&#x7740;&#x5185;&#x90E8;&#x4E8B;&#x52A1;&#x548C;&#x5916;&#x90E8;&#x4E8B;&#x52A1;&#x62FF;&#x5230;&#x7684;bean&#x662F;&#x4E0D;&#x540C;&#x7684;
9.3.3 属性填充populateBean
9.3.3.1填充之前
9.3.3.2 属性注入的原理
  • @Resource,@Autowired,@Value实现的原理 Spring源码学习笔记7——Spring bean的初始化在这篇中我们详细说明了 @Resource,@Autowired,@Value注解的实现原理。 @Autowired和@Value依赖于 AutowiredAnnotationBeanPostProcessor这个后置处理器在其 postProcessMergedBeanDefinition方法中,它会扫描所有bean的字段和方法(父类也会扫描到)将需要进行依赖注入的字段和方法包装成 InjectionMetadata,后续在 postProcessProperties方法中,会循环遍历需要注入的字段和方法,首先会找到合适的注入bean,然后反射进行设置。找到合适的bean依赖的是 DefaultListableBeanFactory#resolveDependency方法 Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点 对于 Optional类型的依赖向,Spring在调用 doResolveDependency后进行包装。对于 ObjectFactory, ObjectProvider类型的依赖项,Spring包装成二者的子类 DependencyObjectProvider调用对应方法的时候还是依赖 doResolveDependency方法找到合适的bean。然后是处理 @Lazy标注的字段或者方法参数,如果存在注解那么spring会使用 ProxyFactory生成代理类,代理类使用了自定义的 TargetSource在使用的时候才会调用 doResolveDependency获取依赖的bean对象。如果没有lazy注解那么直接调用 doResolveDependency方法返回依赖项。 Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点 首先是调用 getSuggestedValue方法解析 @value注解并且进行解析器解析(这就是为什么@Value(环境中的一个key,甚至spel表达式) 可以生效的原型),然后使用类型转换器进行转换(比如配置文件中是字符串但是字段是int,这时候会进行转换),然后是 resolveMultipleBeans方法,它负责解析 Stream,&#x6570;&#x7EC4;&#xFF0C;Collection&#xFF0C;Map类型的,其中 Stream&#xFF0C;&#x6570;&#x7EC4;&#xFF0C;Collection类型会从容器中拿到合适的bean组成流,数组或者集合返回, Map类型则会返回key为bean名称,value为bean的map。找到合适的bean都是调用的 findAutowireCandidates方法,这个方法首先根据注入的类型拿到所有的符合的bean名称,然后还会加上在 resolvableDependencies这个Map中存在符合条件的(ApplicationContext这种不在beanFactory中的bean就是通过这个方法找到的)然后判断bean是否是候选bean,首先要求当前这个候选者对应的bean定义中 isAutowireCandidate方法返回true(这就是为什么@Bean注解注入的对象不会被视作依赖注入的候选者)然后判断是否具备 @Qualifier注解,如果存在那么进行进一步的筛选。然后如果存在多个满足条件的候选者,首先判断 BeanDefinition#isPrimary是否是true(如果存在多个那么本BeanFactory的候选者优先于父BeanFactory,如果还是存在多个抛出异常 NoUniqueBeanDefinitionException)然后比较 javax.annotation.Priority注解中标注的优先级,取最大者,存在多个依旧是 NoUniqueBeanDefinitionException,最后 resolvableDependenciesmap中的候选者,优先于其他候选者。
  • PropertyValues属性注入原理 BeanDefinition.getPropertyValues()这个方法返回bean的属性需要设置的值,一般在xml配置bean的时候比较常用,但是也被用于类似于 Feign扫描接口构建 FactoryBean的时候指定 FactoryBean的属性值。我们实际开发中用得比较少. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点 上图中的例子就是通过 BeanDefinitionRegistryPostProcessor自定义注册 BeanDefinition,并且指定了属性需要注入生么值,其中 str会被注入字符串 straaaa,属性b是 RuntimeBeanReference会被注入名称为 b的bean对象。负责这些属性注入的方法是 applyPropertyValues。最终反射设置值调用的是 BeanWrapper#setPropertyValues方法,Spring会先进行类型转换,然后反射(一般是调用对应的set方法)
9.3.4 bean初始化initializeBean

上面我们学习了Spring是如何实例化bean,并且进行依赖注入的,但是完成这些步骤的bean还没有执行初始化,比如说标记的初始化方法还没有被回调,接下来我们看下是spring是如何实现的

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
9.3.4.1 invokeAwareMethods回调感知接口

这里就是判断是否实现了 BeanNameAware, BeanClassLoaderAware, BeanFactoryAware会调用对应的set方法

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

这里可以看到并没有调用 ApplicationContext因为这是在 DefaultListableBeanFactory中实现的操作, DefaultListableBeanFactory并不知道 ApplicationContext的存在

9.3.4.2初始化之前的后置处理器回调

就是调用所有的 BeanPostProcessor#postProcessBeforeInitialization这里便会调用到

ApplicationContextAwareProcessor,它会负责回调 EnvironmentAware(&#x73AF;&#x5883;&#x611F;&#x77E5;&#x63A5;&#x53E3;), EmbeddedValueResolverAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x4E2D;&#x89E3;&#x6790;&#x5B57;&#x7B26;&#x4E32;&#x503C;&#x7684;&#x7B80;&#x5355;&#x7B56;&#x7565;&#x63A5;&#x53E3;&#x5B9E;&#x73B0;)ResourceLoaderAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x4E2D;&#x7528;&#x4E8E;&#x52A0;&#x8F7D;&#x8D44;&#x6E90;&#xFF08;&#x4F8B;&#x5982;&#x7C7B;&#x8DEF;&#x5F84;&#x6216;&#x6587;&#x4EF6;&#x7CFB;&#x7EDF;&#x8D44;&#x6E90;&#xFF09;&#x7684;&#x7B56;&#x7565;&#x63A5;&#x53E3;&#x5B9E;&#x73B0;)ApplicationEventPublisherAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x4E2D;&#x4E8B;&#x4EF6;&#x53D1;&#x5E03;&#x529F;&#x80FD;&#x7684;&#x63A5;&#x53E3;&#x5B9E;&#x73B0;)MessageSourceAware(&#x53EF;&#x4EE5;&#x62FF;&#x5230;&#x4E0A;&#x4E0B;&#x6587;&#x89E3;&#x6790;&#x6D88;&#x606F;&#x7684;&#x7B56;&#x7565;&#x63A5;&#x53E3;&#x7684;&#x5B9E;&#x73B0;)ApplicationContextAware(spring&#x4E0A;&#x4E0B;&#x6587;&#x611F;&#x77E5;&#x63A5;&#x53E3;)对应的方法

以及 InitDestroyAnnotationBeanPostProcessor(CommonAnnotationBeanPostProcessor的子类,其实是调用到 CommonAnnotationBeanPostProcessor)的 postProcessBeforeInitialization方法,他会调用 @PostConstruct标注的方法。(并且如果容器销毁bean还会调用 @PreDestroy标注的方法)

9.3.4.3初始化方法回调

首先执行 InitializingBean#afterPropertiesSet方法,然后指定自定义在BeanDefinition中的初始化方法。这里可以看到 InitializingBeanSmartInitializingSingleton的区别,前者是每一个bean的初始化的时候调用,后者是所有单例bean预加载之后调用。如果在 InitializingBean中使用容器取getBean那么可能会触发其他bean的加载, SmartInitializingSingleton则不会造成,因为调用的时候已经预加载了所有的非懒加载的单例bean

Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
9.3.4.5 初始化之后的后置处理器回调

调用 BeanPostProcessor#postProcessAfterInitialization这里便是发生动态代理AOP增强的地方(Spring 源码学习笔记10——Spring AOP)

10.finishRefresh

调用 LifecycleProcessor#onRefresh方法,推送 ContextRefreshedEvent的事件

Original: https://www.cnblogs.com/cuzzz/p/16662905.html
Author: Cuzzz
Title: Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/610112/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 循序渐进nginx(三):日志管理、http限流、https配置,http_rewrite模块,第三方模块安装,结语

    日志管理 access_log error_log 日志文件切割 自定义错误页 http访问限流 限制请求数 语法 使用 限制连接数 语法 测试 补充: https配置 使用 生成…

    Java 2023年5月30日
    091
  • 2018年最新JAVA面试题总结之数据库(3)

    转自于:https://zhuanlan.zhihu.com/p/39804394 1、MySQL的delete与truncate区别? 回答:delete语句执行删除的过程是每次…

    Java 2023年6月13日
    076
  • JDK1.8 LongAdder 空间换时间: 比AtomicLong还高效的无锁实现

    我们知道,AtomicLong的实现方式是内部有个value 变量,当多线程并发自增,自减时,均通过CAS 指令从机器指令级别操作保证并发的原子性。 先看LongAdder的add…

    Java 2023年5月30日
    076
  • SimpleDateFormat线程不安全的5种解决方案

    1.什么是线程不安全? 线程不安全也叫非线程安全,是指多线程执行中,程序的执行结果和预期的结果不符的情况就叫着线程不安全。 线程不安全的代码 SimpleDateFormat 就是…

    Java 2023年5月30日
    086
  • 【源码笔记】构建Spring源码环境

    IDEA构建Spring源码,不成功你来抓我 posted @2022-07-14 22:43 daheww 阅读(15 ) 评论() 编辑 Original: https://w…

    Java 2023年6月6日
    084
  • HTML基础笔记整理

    「学习笔记」HTML基础 勤做笔记不仅可以让自己学的扎实,更重要的是可以让自己少走弯路。有人说:”再次翻开笔记是什么感觉”,我的回答是:”初恋般…

    Java 2023年6月7日
    076
  • 设计模式学习笔记(十一)外观模式及其应用场景

    外观(Facade)模式,又叫做门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问的模式。比如说我们日常生活中医院的分诊台,就是实现统一访问接口的…

    Java 2023年6月6日
    095
  • vnpy源码阅读学习(7):串在一起

    串在一起 我们已经分析了UI、MainEngine、EventEngine。然后他们几个是如何发挥作用的呢?我总结了一张图: 我们来具体的看看UI部分是如何跟EventEngine…

    Java 2023年6月7日
    038
  • 【翻译】Nginx的HTTP负载均衡

    将请求负载均衡到多个应用实例是一个常用的技术,它起到优化资源使用率、最大化吞吐量、降低延迟、保证容错性。 Nginx是一个非常有效的HTTP负载均衡工具,它将请求分发到多个应用服务…

    Java 2023年5月30日
    064
  • JAVA设计模式之—抽象工厂模式(AbstractFactoty)

    一、概述 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 二、为何使用 工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在J…

    Java 2023年6月8日
    0110
  • windows下nginx安装、配置与使用

    目前国内各大门户网站已经部署了Nginx,如新浪、网易、腾讯等;国内几个重要的视频分享网站也部署了Nginx,如六房间、酷6等。新近发现Nginx 技术在国内日趋火热,越来越多的网…

    Java 2023年5月30日
    055
  • SpringCloud整合WebSocket实现用户监控

    @ 前言 一、建项目 + 1. 在父项目ams-cloud下建立maven子项目ams-websocket 2.pom文件添加常用依赖,另外添加redis依赖等,我这里直接引用co…

    Java 2023年6月13日
    075
  • MySQL相关事项

    重启MySQL service mysql stop service mysql start service mysql restart 创建MySQL用户并允许远程访问 CREA…

    Java 2023年6月5日
    070
  • Mysql数据库学习

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月7日
    068
  • Elasticsearch必备原理理解

    Elasticsearch读写原理 心得: 主分片、副本分片的存在类似各大组件的”主从结构”,需要注意的是,Elasticsearch的写入是针对 主分片,…

    Java 2023年6月6日
    082
  • IBM MQ Explorer 示例操作

    此示例为双向传输 建立队列管理器 建立【test01】【test02】两个队列管理器,一直下一步即可,端口号不能一致(需要记住设置的端口号,后面会用到) 【test01】端口号 1…

    Java 2023年5月29日
    074
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球