参考了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四个对象都依赖与彼此,耦合度很高。
IoC理论出现后,多了一个中间件——IoC容器(万能的解耦方案,耦合度高了就加一层)
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#
1.什么是spring bean#
Spring Bean是指Spring 容器管理的对象,一个Spring 容器管理多个Spring bean,对它们进行实例化,依赖注入,初始化等。这些 bean 是使用我们提供给spring容器的配置元数据创建的(例如,以 XML
定义的形式)。
在容器中,这些 bean 定义表示为BeanDefinition
对象,其中包含以下元数据:
- 一个包限定的类名:通常是被定义的 bean 的全限定类名,实际实现类。
- Bean 行为配置元素,它说明 bean 在容器中的行为方式(作用域、生命周期回调等)。
- 当前bean 依赖的其他bean。
- 等等
2.BeanDefinition#
BeanDefinition
描述了一个 bean 实例,它记录了bean的属性值、构造函数参数值以及其他更多信息。BeanDefinition
在Spring 管理bean中至关重要,指导了Spring 依据BeanDefinition
生成Bean,bean的作用域,是否懒加载等等。
BeanDefinition
中具有设置和获取 此bean 定义的父BeanDefinition的名称(如果有)
,bean 类名
,Bean的作用域
,Bean是否懒加载
,当前bean依赖的bean名称
,是否Autowire候选者
,是否是最主要的自动装配候选者
,初始化方法名称
,销毁方法名称
,是否单例
,是否原型
,bean属性值
。
传统的基于XML Spring 容器便是使用对应的BeanDefinitionReader
解析XML将xml中的信息包装成BeanDefinition
保存到Spring容器中,后续由Spring容器根据BeanDefinition
对Bean进行管理。
3.BeanDefinitionReader#
Bean定义信息读取器,定义了如下方法
BeanDefinitionReader
的典型实现莫过于XmlBeanDefinitionReader
,它负责解析xml生成BeanDefinition并注册(spring源码学习笔记1——解析xml生成BeanDefinition的过程解析)
这个类关系图中有两个异类AnnotatedBeanDefinitionReader
,ClassPathBeanDefinitionScanner
,它们没有实现BeanDefinitionReader
但是存在的目的和BeanDefinitionReader
是一致的——将生成BeanDefinition并注册到容器,并且根据配置生成beanDefinition的动作交给他们,并不是直接让BeanFactory来完成,更加可扩展,更加单一职责。
4.BeanDefinitionRegistry#
Bean定义注册中心,主要是对BeanDefinition
的增删改查,自然内部会对BeanDefinition
信息进行存储。
DefaultListableBeanFactory
是一个Bean工厂,Spring中很多上下文都是通过组合它来实现对Bean的管理。其中还涉及到AliasRegistry
顾名思义就是对bean的别名进行管理。
三丶BeanFactory类结构体系#
Spring 容器的根接口,主要提供了getBean
(根据bean名称,类型等获取bean的方法),以及判断bean是否单例,是否原型等方法。Spring建议BeanFactory
的实现类尽可能的支持bean的生命周期接口的回调(比如InitializingBean#afterPropertiesSet
等)其中最关键的实现类莫过于DefaultListableBeanFactory
。
1.从DefaultListableBeanFactory看BeanFactory类结构体系#
-
HierarchicalBeanFactory
层次结构的BeanFactory
提供两个方法getParentBeanFactory
获取当前BeanFactory
的父工厂,containsLocalBean
当前BeanFactory
是否包含指定名称的bean -
ListableBeanFactory
可罗列的BeanFactory
,这里的可罗列意味着此BeanFactory
提供类似于
这种获取满足条件的一系列bean的功能Map getBeansOfType(@Nullable Class type) -
AutowireCapableBeanFactory
具备自动装备功能的BeanFactory
,提供了createBean实例化,属性填充,回调生命周期的创建bean
,autowire自动装配bean
,initializeBean 回调相关初始化方法
,等方法 -
ConfigurableBeanFactory
可配置的BeanFactory
,提供了setParentBeanFactory
,setBeanClassLoader
,addBeanPostProcessor
等配置bean工厂的方法 -
ConfigurableListableBeanFactory
,实现了ListableBeanFactory
,AutowireCapableBeanFactory
,ConfigurableBeanFactory
,具备其他三者的功能的同时,还提供了ignoreDependencyType 忽略给定依赖类型的自动装配
,registerResolvableDependency 注册指定类型的依赖使用指定的对象进行注入
等功能
2.从DefaultListableBeanFactory 看注册系接口#
-
AliasRegistry
:别名注册,SimpleAliasRegistry
是主要的实现,内部使用一个ConcurrentHashMap
存储bean名称和别名 -
BeanDefinitionRegistry
Bean定义注册中心,主要是对
BeanDefinition
的增删改查 -
SingletonBeanRegistry
单例bean注册,提供注册单例,获取单例,等方法
四丶ApplicationContext类结构体系#
1.ApplicationContext类结构体系分析#
从类图我们可以看到BeanFactory
和ApplicationContext
的区别,总体来说ApplciationContext
是一个BeanFactory
但是包含其他更多的功能,这些功能就在它实现的其他接口体现
EnvironmentCapable
提供获取Environment
的能力ResourceLoader
:用于加载资源(例如类路径或文件系统资源)的策略接口,根据路径获取资源包装成Resource
ResourcePatternResolver
:ResourceLoader
的子接口,提供根据路径匹配获取资源的能力ApplicationEventPublisher
事件发送接口MessageSource
:用于解析消息的策略接口,用于实现国际化
2.ClassPathXmlApplicationContext类结构体系分析#
基于类路径下xml文件的Spring应用程序上下文,通过解析类路径下的xml来加载Spring容器
ConfigurableApplicationContext
可拱配置的Spring容器上下文,支持添加事件监听器,设置父容器,设置环境,设置后置处理器等操作AbstractApplicationContext
通过组合的方式,实现容器上下文的功能。提供了诸多模板方法,并且定义了Spring容器刷新的基本逻辑,其中定义了refreshBeanFactory
在spring容器刷新的时候触发BeanFactory
的刷新AbstractRefreshableApplicationContext
实现了refreshBeanFactory
定义了刷新BeanFactory
的流程——创建BeanFactory
,加载BeanDefinition
(抽象方法交给子类实现)AbstractRefreshableConfigApplicationContext
实现了InitializingBean
在afterPropertiesSet
方法中调用容器刷新的refresh
方法AbstractXmlApplicationContext
抽象的xml上下文,对从xml加载BeanDefinition
进行了实现,提供了getConfigResources
方法让子类自定义xml文件的来源
3.AnnotationConfigApplicationContext类结构体系分析#
基于注解包路径扫描的容器上下文,内部持有AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner
来完成BeanDefinition
的注册
GenericApplicationContext
内部持有一个DefaultListableBeanFactory
,并且继承了BeanDefinitionRegistry
提供注册BeanDefinition
的方法,但是refresh
方法不会去加载资源下的BeanDefinition
,不像ClassPathXmlApplicationContext
一样会根据路径加载BeanDefinition
AnnotationConfigRegistry
,提供register(注册一个或多个要处理的注解类)
和scan(在指定包路径中执行扫描)
方法
五丶ApplicationContext#refresh#
ApplicationContext#refresh
方法是Spring源码学习中最重要的方法,是Spring容器启动会执行的方法,涉及到BeanDefinition的扫描,单例bean的生成等等。下面我们从AbstractApplicationContext
对refresh
方法简单分析下,Spring容器启动到底做了些什么
1.刷新BeanFactory#
这部分会调用refreshBeanFactory
(抽象方法交由子类实现),实现对BeanFactory的刷新,对于AbstractRefreshableApplicationContext
的子类会在其中销毁原有的BeanFactory然后重写创建BeanFactory,对于GenericApplicationContext
子类什么都不会做。
体现在ClassPathXmlApplicationContext
会根据配置的xml路径重新解析xml生成BeanDefinition并注册,对于AnnotationConfigApplicationContext
则是什么都不做。
1.1 AbstractRefreshableApplicationContext#refreshBeanFactory 加载BeanDefinition#
loadBeanDefinitions
是一个抽象方法,具体如何加载BeanDefinition
交给子类去实现,ClassPathXmlApplication
加载BeanDefinition的流程在其父类AbstractXmlApplicationContext
中内部使用XmlBeanDefinitionReader#reader
方法读取Resouce
生成BeanDefinition
1.2GenericApplicationContext的子类是如何加载BeanDefinition的#
以AnnotationConfigApplicationContext
为例
其构造方法,如果传入的是一个包路径,那么会调用无参构造方法,从而new 出AnnotatedBeanDefinitionReader
和ClassPathBeanDefinitionScanner
,然后使用ClassPathBeanDefinitionScanner
扫描包下的所有具备@Component
注解(包括复合注解)的类,如果传入的是若干个类那么AnnotatedBeanDefinitionReader
会对这些类进行注册。
2.prepareBeanFactory前缀准备#
这部分主要是对ConfigurableListableBeanFactory
进行一些设置。其中会加入一个ApplicationContextAwareProcessor
和ApplicationListenerDetector
的BeanPostProcessor
,并且忽略EnvironmentAware
,EmbeddedValueResolverAware
,ResourceLoaderAware
,ApplicationEventPublisherAware
,MessageSourceAware
,ApplicationContextAware
等接口自动装配,并且注册BeanFactory
,ResourceLoader
,ApplicationEventPublisher
,ApplicationContext
的自动装配值(依赖注入的时候,会使用注册的值进行设置)
3.postProcessBeanFactory#
留给子类扩展的方法,对于web应用上下文会在其中设置ServletContextAwareProcessor
的BeanPostProcessor
,并且注册request和 session的scope
4.invokeBeanFactoryPostProcessors 调用BeanFactoryPostProcessor#
此方法会对BeanDefinitionRegistryPostProcessor
和BeanFactoryPostProcessor
中的方法进行调用。调用通过ConfigurableApplicationContext#addBeanFactoryPostProcessor
添加的,或者BeanFactory
中BeanDefinitionRegistryPostProcessor
和BeanFactoryPostProcessor
类型的bean的bean名称,getBean
方法实例化后调用
4.1 什么是BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor#
BeanFactoryPostProcessor
:Spring留给我们的一个扩展接口,在BeanDefinition
加载注册完之后,并执行一些前置操作之后会实例化所有的BeanFactoryPostProcessor
实例并且回调对应postProcessBeanFactory
方法。允许自定义修改应用程序上下文的 bean 定义,调整上下文底层 bean 工厂的 bean 属性值。应用程序上下文可以在其 bean 定义中自动检测 BeanFactoryPostProcessor bean,并在创建任何其他 bean 之前应用它们。BeanDefinitionRegistryPostProcessor
:BeanFactoryPostProcessor
的子类,新增postProcessBeanDefinitionRegistry
方法,在检测``BeanFactoryPostProcessor类型的
BeanDefinition之前就会调用所有
BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry,这个方法允许我们新增,修改,删除,查找之前注册的
BeanDefinition,所有可以在这个方法中对
BeanFactoryPostProcessor进行调整,也可以对其他所有
BeanDefinition`进行调整
4.2 重要的BeanFactoryPostProcessor#
4.2.1 PropertyPlaceholderConfigurer
#
它根据本地属性,系统属性和环境变量解析 ${...}
占位符,会替换掉BeanDefinition
中的占位符。这也是基于xml配置数据源的时候可以把数据库配置放在一个文件中,然后通过占位符进行引用
4.2.2 EventListenerMethodProcessor
#
其postProcessBeanFactory
会实例化EventListenerFactory
并且持有,并且它继承了SmartInitializingSingleton
在afterSingletonsInstantiated
方法中,会把每一个在方法中标注了@EventListener
(或其复合注解)的bean和方法包装成ApplicationListener
注册到Spring上下文(其实是委托给对于的事件多播器ApplicationEventMulticaster
)
为啥@Aysnc注解可以搭配@EventListener实现异步的效果
afterSingletonsInstantiated调用实际是所有单例bean初始化后
这时候bean已近是被@Aysnc对于的BeanPostProcessor进行CGLIB增强的bean了
调用方法便以及是异步调用的了
其实spring的默认的多播器SimpleApplicationEventMulticaster,内部持有一个JUC的Executor,可以配置成线程池,那么就是不需要@Aysnc也能异步调用
4.2.3ConfigurationClassPostProcessor
#
解析加了@Configuration
的配置类,还会解析@ComponentScan
、@ComponentScans
注解扫描的包,以及解析@Bean,@Import,@PropertySources,@ImportResource
等注解,将这些注解信息解析成BeanDefinition
注册到Spring BeanFactory中。
4.2.4 工作中碰到的用法#
其实和PropertyPlaceholderConfigurer
差不多,公司为了避免配置文件中明文存储数据库密码,采用一种加密方式配置文件存储加密后的密文,然后用SpringBoot的自动配置注入一个BeanFactoryPostProcessor进行解密。
5.registerBeanPostProcessors 注册BeanPostProcessor#
5.1 什么是BeanPostProcessor#
一个允许自定义修改新 bean 实例的接口,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的
5.2 registerBeanPostProcessors的逻辑#
获取BeanFactory中的BeanPostProcessor类型的bean,根据实现PriorityOrdered中的getOrder方法顺序
>实现Ordered中getOrder方法的顺序
>@Order标注的顺序
>没有实现这两个接口也没有标注注解的顺序
(是否支持@Order
注解排序,取决于BeanFactory使用的比较器)
5.3 BeanPostProcessor 类结构体系#
5.3.1 BeanPostProcessor#
提供两个方法:postProcessBeforeInitialization(在bean初始化方法调用之前被Spring容器调用)
,postProcessAfterInitialization(在bean初始化方法调用之后调用)
5.3.2 MergedBeanDefinitionPostProcessor#
在BeanPostProcessor的基础上新增一个方法postProcessMergedBeanDefinition
在创建bean时,会先获取bean对应的BeanDefinition(Spring可能对存在父子关系的beanDefinition进行合并)后,spring会实例化bean然后会调用postProcessMergedBeanDefinition
,入参中有BeanDefinition
可以进行自定义的修改
5.3.3 InstantiationAwareBeanPostProcessor#
在BeanFactoryPostProcessor的基础新增postProcessBeforeInstantiation(在Spring实例化bean之前调用,返回非空对象可以阻断Spring后续实例化,属性填充,初始化方法的调用咯流程)
,postProcessAfterInstantiation(在实例化 bean 之后,但在 Spring 属性填充发生执行操作)
,postProcessProperties在spring将给定的属性值应用到给定的 bean 后调用
5.3.4 DestructionAwareBeanPostProcessor#
在BeanFactoryPostProcessor的基础新增postProcessBeforeDestruction在bean被销毁之前调用
。
5.3.5 SmartInstantiationAwareBeanPostProcessor#
在InstantiationAwareBeanPostProcessor
的基础新增determineCandidateConstructors(Spring会推断构造方法来反射生成对象,这个方法可以决定使用哪些构造方法)
,getEarlyBeanReference(获取对指定 bean 的早期暴露的引用,如果出现循环依赖,获取对象的时候会调用此)
5.4 Spring源码中BeanPostProcessor的应用#
5.4.1 ApplicationContextAwareProcessor#
负责EnvironmentAware(环境感知接口)
,EmbeddedValueResolverAware(可以拿到上下文中解析字符串值的简单策略接口实现)
,ResourceLoaderAware(可以拿到上下文中用于加载资源(例如类路径或文件系统资源)的策略接口实现)
,ApplicationEventPublisherAware(可以拿到上下文中事件发布功能的接口实现)
,MessageSourceAware(可以拿到上下文解析消息的策略接口的实现)
,ApplicationContextAware(spring上下文感知接口)
接口的回调,回调对于的set方法
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
并缓存,后续在determineCandidateConstructors
和postProcessProperties
中发挥作用
5.4.4 CommonAnnotationBeanPostProcessor#
在Spring源码学习笔记7——Spring bean的初始化 学习过,负责解析@PostConstruct
,@PreDestroy
,@Resource
,在postProcessMergedBeanDefinition
中会把@PostConstruct
,@PreDestroy
标注的方法包装成LifecycleMetadata
,其中PostConstruct
标注的放法会在postProcessBeforeInitialization(实例化之后,初始化之前)
中被调用,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注册监听器#
负责把事件监听器 注册到多播器中,并且在事件多播器初始化执行之前,可能存在一些事件没有处理,这些事件都会放在earlyApplicationEvents集合中,在多播器初始化后,会把earlyApplicationEvents置为null 以后的事件都是直接委托给多播器进行推送。
9.finishBeanFactoryInitialization实例化所有非懒加载的单例bean#
这个方法贯穿了bean的实例化,属性填充,初始化。
Spring源码学习笔记6——Spring bean的实例化
Spring源码学习笔记7——Spring bean的初始化
Spring源码学习笔记8——Spring是如何解决循环依赖的
这四篇笔记中详细的说明了Bean的初始化流程,下面我进行粗略的总结,提前初始化单例bean的方法是DefaultListableBeanFactory#preInstantiateSingletons
在DefaultListableBeanFactory#preInstantiateSingletons
存在两个for循环,第一个是实例化加载所有的单例非懒加载bean,第二个for循环是在加载完后,调用实现了SmartInitializingSingleton
接口bean的afterSingletonsInstantiated
方法,这是spring留给我们的一个扩展接口
9.1.什么样的bean才会被实例化#
首先要满足!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()
,即不是抽象,且单例,且不是懒加载的BeanDefinition
9.2 FactoryBean和普通bean的不同处理#
-
什么是FactoryBean
FactoryBean
是spring留给我们创造复杂对象的一个接口,可以把它看作是制造bean的一个工厂,Spring如果发现BeanDefinition中的bean类型是FactoryBean那么会调用FactoryBean#getObject
方法产生bean。 -
创建FactoryBean 和 其对应的bean
首先如果是FactoryBean 那么bean名称前面会有FactoryBean专属的前缀
&
,Spring会先初始化FactoryBean然后如果是SmartFactoryBean
并且渴望初始化那么会调用getBean
,这个方法发现制造的bean对应的BeanDefinition
记录的类型是FactoryBean那么会调用FactoryBean的getObject
方法。而普通bean直接调用getBean
方法创建,也就是说FactoryBean类型的bean,如果不是SmartFactoryBean
且渴望加载,那么Spring容器启动之后加载FactoryBean——有点懒加载的意思。
9.3 Spring创建bean#
上面我们看到初始化所有懒加载单例bean调用的是BeanFactory#getBean(beanName)
,这里的BeanFactory一般是DefaultSingletonBeanRegistry
其内部使用map组成三级缓存,并且还要对factoryBan的缓存,如下图
下面我们看下创建bean的逻辑
9.3.1前置逻辑 factoryBean和父beanFactory相关#
首先是一级缓存即单例池中获取,如果之前之前创建过单例对象,那么会被缓存到一级缓存单例池中,这时候就直接拿到了,但是拿到的可能是FactoryBean
,所有调用getObjectForBeanInstance
方法,如果是FactoryBean那么会调用其getObject
生成bean。如果当前BeanFactory没有此beanName对应的BeanDefinition那么会调用父beanFactroy的getBean
方法。反之说明存在对应的beanDefinition这时候就是取创建bean的流程了
9.3.2 实例化bean——createBeanInstance方法#
9.3.2.1 实例化单例对象#
创建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使用prototypesCurrentlyInCreation
ThreadLocal保存了原型对象是否处于创建中,如果发送循环依赖那么将抛出异常
9.3.2.3实例化特殊作用域的bean#
这里说是实例化,其实是实例化+属性填充+初始化
之所以说实例化,是因为单例,原型,特殊作用域的bean只是实例化触发的条件不同
单例只实例化一次
原型每次getBean都实例化
特殊作用域取决于作用域的逻辑
我们重点关注下Scope#get
方法,它是如何控制作用域的,此方法的含义是先尝试在Scope中拿(一般是一个缓存,Map或者ThreadLocal)如果没有那么调用后续传入的lambda。
-
SessionScope 和 RequestScope
session 和request 范围
SessionScope 和 RequestScope 都是基于
RequestContextHolder
(内部使用requestAttributesHolder的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
什么样的,事务被视作时一个独立事务昵
如果外部不存在一个事务,并且传播级别是REQUIRED,REQUIRES_NEW,NESTED
如果外部存在一个事务,且传播级别为REQUIRES_NEW
如果外部存在一个事务,且传播级别为嵌套事务,但是此时不是通过保存点来实现嵌套事务
上面三个条件也意味着内部事务和外部事务拿到的bean是不同的
9.3.3 属性填充populateBean#
9.3.3.1填充之前#
- 会调用
MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
让我们自定义修改合并后的BeanDefinition(每一个beanDefinition存在一个标识符记录是否被处理过后,只会被处理一次) - 如果当前创建的是单例bean,并且允许循环依赖那么会把当前bean和
getEarlyBeanReference
方法封装成ObjectFactory
存入到三级缓存,这一步是是为了解决循环依赖发生时,需要BeanPostProcessor进行后置处理的问题(Spring源码学习笔记8——Spring是如何解决循环依赖的,Spring源码学习笔记9——构造器注入及其循环依赖)
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
方法对于
Optional
类型的依赖向,Spring在调用doResolveDependency
后进行包装。对于ObjectFactory
,ObjectProvider
类型的依赖项,Spring包装成二者的子类DependencyObjectProvider
调用对应方法的时候还是依赖doResolveDependency
方法找到合适的bean。然后是处理@Lazy
标注的字段或者方法参数,如果存在注解那么spring会使用ProxyFactory
生成代理类,代理类使用了自定义的TargetSource
在使用的时候才会调用doResolveDependency
获取依赖的bean对象。如果没有lazy注解那么直接调用doResolveDependency
方法返回依赖项。首先是调用
getSuggestedValue
方法解析@value
注解并且进行解析器解析(这就是为什么@Value(环境中的一个key,甚至spel表达式) 可以生效的原型),然后使用类型转换器进行转换(比如配置文件中是字符串但是字段是int,这时候会进行转换),然后是resolveMultipleBeans
方法,它负责解析Stream,数组,Collection,Map
类型的,其中Stream,数组,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
,最后resolvableDependencies
map中的候选者,优先于其他候选者。 -
PropertyValues属性注入原理
BeanDefinition.getPropertyValues()
这个方法返回bean的属性需要设置的值,一般在xml配置bean的时候比较常用,但是也被用于类似于Feign
扫描接口构建FactoryBean
的时候指定FactoryBean
的属性值。我们实际开发中用得比较少.上图中的例子就是通过
BeanDefinitionRegistryPostProcessor
自定义注册BeanDefinition
,并且指定了属性需要注入生么值,其中str
会被注入字符串straaaa
,属性b是RuntimeBeanReference
会被注入名称为b
的bean对象。负责这些属性注入的方法是applyPropertyValues
。最终反射设置值调用的是BeanWrapper#setPropertyValues
方法,Spring会先进行类型转换,然后反射(一般是调用对应的set方法)
9.3.4 bean初始化initializeBean#
上面我们学习了Spring是如何实例化bean,并且进行依赖注入的,但是完成这些步骤的bean还没有执行初始化,比如说标记的初始化方法还没有被回调,接下来我们看下是spring是如何实现的
9.3.4.1 invokeAwareMethods回调感知接口#
这里就是判断是否实现了BeanNameAware
,BeanClassLoaderAware
,BeanFactoryAware
会调用对应的set方法
这里可以看到并没有调用ApplicationContext
因为这是在DefaultListableBeanFactory
中实现的操作,DefaultListableBeanFactory
并不知道ApplicationContext
的存在
9.3.4.2初始化之前的后置处理器回调#
就是调用所有的BeanPostProcessor#postProcessBeforeInitialization
这里便会调用到
ApplicationContextAwareProcessor
,它会负责回调EnvironmentAware(环境感知接口)
,EmbeddedValueResolverAware(可以拿到上下文中解析字符串值的简单策略接口实现)
,ResourceLoaderAware(可以拿到上下文中用于加载资源(例如类路径或文件系统资源)的策略接口实现)
,ApplicationEventPublisherAware(可以拿到上下文中事件发布功能的接口实现)
,MessageSourceAware(可以拿到上下文解析消息的策略接口的实现)
,ApplicationContextAware(spring上下文感知接口)
对应的方法
以及InitDestroyAnnotationBeanPostProcessor
(CommonAnnotationBeanPostProcessor
的子类,其实是调用到CommonAnnotationBeanPostProcessor
)的postProcessBeforeInitialization
方法,他会调用@PostConstruct
标注的方法。(并且如果容器销毁bean还会调用@PreDestroy
标注的方法)
9.3.4.3初始化方法回调#
首先执行InitializingBean#afterPropertiesSet
方法,然后指定自定义在BeanDefinition中的初始化方法。这里可以看到InitializingBean
和SmartInitializingSingleton
的区别,前者是每一个bean的初始化的时候调用,后者是所有单例bean预加载之后调用。如果在InitializingBean
中使用容器取getBean那么可能会触发其他bean的加载,SmartInitializingSingleton
则不会造成,因为调用的时候已经预加载了所有的非懒加载的单例bean
9.3.4.5 初始化之后的后置处理器回调#
调用BeanPostProcessor#postProcessAfterInitialization
这里便是发生动态代理AOP增强的地方(Spring 源码学习笔记10——Spring AOP)
10.finishRefresh#
调用LifecycleProcessor#onRefresh
方法,推送ContextRefreshedEvent
的事件