Spring 的 bean 初始化過程
前言
Spring 框架最基礎來說, 是一個 DI(依賴注入) 框架. 我們把我們的程序中用到的實體對象, 也就是我們常說的 bean, 放在 Spring 框架中維護, 當我們用到這些 bean 的時候, 可以在程序的任何地方來獲取.
Spring 封裝了復雜的邏輯, 留給了我們很多便利又簡單的方式來使用, 這正是我們使用 spring 框架的原因. 但是這也帶來了一些問題, 我們對內部幾乎一無所知, 當遇到復雜情況或者問題的時候, 往往無從下手. 而且, 隨著 spring 很多自動化配置的出現(xiàn), 和我們印象中的一些配置方式產生了沖突或重復, 即使在通常情況下能夠啟動運行, 我們也不敢說我們的配置絕對正確沒有問題. 這個時候, 我覺得我們應該多了解一些內部實現(xiàn), 這對于我們排查異常問題, 檢查項目正確性都很有幫助.
那么我們在使用時, 就涉及到兩個方面:
- 定義和注冊 bean
- 獲取 bean
我們從這兩個方面來講.
定義和注冊 bean
我們在使用 spring 的時候, 有這么幾種常用的定義 bean 的方式:
- xml 中來定義 bean 標簽
- 通過注解掃描, 比如 @Service 這種類.
- 定義 Configuration 類, 在類中提供 @Bean 的方法來定義.
- 使用純粹的 programmatically 的方式來定義和注冊.
前三種方式, 我們經常使用, 我們簡單看一下第四種方式是什么樣子的
// 新建一個工廠
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 新建一個 bean definition
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder
.genericBeanDefinition(SomeService.class)
.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
// 注冊到工廠
factory.registerBeanDefinition("someService", beanDefinition);
// 自己定義一個 bean post processor. 作用是在 bean 初始化之后, 判斷這個 bean 如果實現(xiàn)了 ApplicationContextAware 接口, 就把 context 注冊進去..(先不要管 context 哪來的...例子嘛)
factory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextAware) {
GenericApplicationContext context = new GenericApplicationContext(factory);
((ApplicationContextAware) bean).setApplicationContext(context);
}
return bean;
}
});
// 再注冊一個 bean post processor: AutowiredAnnotationBeanPostProcessor. 作用是搜索這個 bean 中的 @Autowired 注解, 生成注入依賴的信息.
AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
autowiredAnnotationBeanPostProcessor.setBeanFactory(factory);
factory.addBeanPostProcessor(autowiredAnnotationBeanPostProcessor);
// getBean() 時, 初始化
SomeService SomeService = factory.getBean("someService",SomeService.class);
SomeService.doSomething();
我們定義了一個 BeanDefinition, 注冊到了一個 BeanFactory 中; 然后從 BeanFactory 中獲得這個 bean, 調用這個 bean 當中的方法.
事實上, 定義 BeanDefinition 并注冊到 BeanFactory 的這個過程, 就是 bean 的定義和注冊 , 我們通常使用 spring 時并不是把一個 bean 的實例注冊, 而是一個 BeanDefinition.
而在第一次從 BeanFactory 當中 getBean() 時, 這個 bean 的實例才會真正生成. 這個部分我們在第二部分講.
BeanFactory
BeanFactory 是專門用來獲取 bean 的接口. 他又諸多的實現(xiàn), 其中 ConfigurableListableBeanFactory 是最常用的.
另外 Context 類也實現(xiàn)了 BeanFacotry 的接口, Context 是通過繼承和組合的方式對 BeanFactory 的一層封裝, 避免直接訪問到 BeanFactroy, 保證運行時不能隨意對 BeanFactroy進行修改. 除此之外還提供了更多的功能: 它不僅有 BeanFactory 管理 bean 池的功能, 還要負責環(huán)境配置管理, 生命周期管理, 復雜的初始化操作等.
BeanFactory 的接口成層次比較復雜, 我總結了下主要的有以下功能的接口
-
BeanFactroy
最基礎的 BeanFactory, 提供了根據 name , type 等獲取一個 bean 對象的能力
-
ListableBeanFactory
繼承 1, 額外提供了列出所有bean對象的能力
-
HierarchialBeanFacotry
繼承 1, 額外使了 factory 擁有一個 parent factory 的能力, 可以存在層級關系
-
singletonbeanRegistry
提供了單例對象緩存的能力
-
AutowireCapableBeanFacory
繼承 1, 提供了在創(chuàng)建對象時, 通過set方式給 bean 初始化 autowired 或者聲明了 dependon 的成員
-
ConfigurableBeanFactory
繼承 2 和 3, 給 factory 提供了很多配置的方法, 比如設置 BeanPostProcessor
-
AliasRegistry
支持了多個別名
最終經過各種組合, 我們一般用到實現(xiàn)類就兩個
-
StaticListableBeanFactory
實現(xiàn) ListableBeanFactory, 是最簡單的 Beanfactory. 直接注冊 bean 實例到 factory 中的 map 中, 獲取時直接從 map 中返回. 如果我們自己寫的簡單項目需要做基本的依賴注入管理, 可以使用這一個.
-
DefaultListableBeanFactory
我們平常項目用到的, 通過 BeanDefinition 定義類, 在第一次 get 時實例化, 并在實例化過程中同時實例化依賴類, 并做屬性填充, 并執(zhí)行一些初始化前后的 processor.
我們平常從 xml 中, 代碼注解中定義的 bean, 通過 XmlBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 生成 bean definition 注冊到 DefaultListableBeanFactory中.
我們就從 DefaultListableBeanFactory 來講初始化的過程, 如果想通過這個類來創(chuàng)建 bean , 就需要通過 xml配置, bean配置的方式生成 bean definition, 這是個怎樣的東西呢.
BeanDefinition
完全的定義了一個 bean 的實例化, 初始化方式.
我們可能會關心的內部屬性
parentName: String // bean 的名字
beanClassName: String // bean 類型名字
scope: String // 作用域, 默認的有 singleton 和 proto, 前者是我們常用的單例, 后者是每次新建一個 bean. 子類可以實現(xiàn)更多的scope, 比如 session, request.
lazyInit: boolean // 是否需要懶加載, 通常是由有context的應用來控制.
dependsOn: String[] // 依賴的 bean name, 跟是否要注入沒關系, 有時是因為要控制 bean 的初始化順序
autowireCandidate: boolean // 是否可以被 autowire, 默認true
primary: boolean // autowire 的優(yōu)先級, 如果有多個 candidate, 會選 primary
factoryBeanName: String // 如果實例需要由工廠創(chuàng)建, 工廠 bean 的 name.
factoryMethodName: String // 工廠 bean 的 類型.
constructorArgumentValues: ConstructorArgumentValues // 構造函數參數表
propertyValues: MutablePropertyValues // 屬性表
singleton: boolean
prototype: boolean
abstract: boolean
role: int // bean 的定義者, 0: 由application定義, 即用戶定義的. 1: support, 框架支持模塊. 2: infrastructure, 框架的基礎組件
description: String
resourceDescription: String // 定義來源
originatingBeanDefinition: BeanDefinition // 加工后的 BeanDefinition 保存原始 BeanDefinition.
beanClass: Class<?> // load bean 的 class 之后, 把 class 類型保存這里
abstract: boolean
autowireMode: int // 可以被autowire按類型, 按名稱等
resolvedAutowireMode: int // 解決自己autowire屬性時用按類型注入, 還是按構造參數傳入
dependencyCheck: int // 依賴 check 策略, 全都 check, 還是只 check 引用類型, 還是只 check 簡單類型, 或者不 check
initMethodName: String // 自定義的初始化方法
destroyMethodName: String // 銷毀方法
synthetic: boolean // true 表示不需要多余的 實例化,初始化前后處理.
resource: Resource // 這個 bean definition 的 resource 引用
Bean的實例化過程
大概流程及說明, 以 singleton scope 的 bean 為例
-
get bean from singleton cache
首先從 singleton cache 獲取對象, 如果有, 說明初始化過, 直接返回, 如果沒有, 繼續(xù)
if return bean, return
if null, go on
-
create merged definition
找到 bean 的 definition (bd), 然后生成 merged bean definition (mbd). 這個主要是因為 bd 可以有 parent, 這個步驟的作用就是把 bd 和 它的 parent bd (如果有的話), 進行merge, 生成 mbd, 之后就要根據這個 mbd 來實例化和初始化 bean.
-
check bean definition
檢查 mbd , 把 mbd 中 dependsOn 的 bean 都先初始化.
-
get singleton, if not found, then create bean:
再次從 singleton cache 中獲取 bean, 跟第 1 步方法參數不同, 這一步如果沒有, 則會真正 create bean
-
resolve class
查找并 load 這個 bean 的 class
-
resolveBeforeInstantiation
在真正的實例化之前進行一次預先操作, 目的是給用戶一個機會來進行非正常的實例化, 用戶注入的 InstantiationAwareBeanPostProcessor 子類, 可以做一些 proxy, mock, 來取代真實的實例化返回, 如果沒有產生 bean, 則繼續(xù)往下走去正常的實例化階段.
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
- if return bean, BeanPostProcessor.postProcessAfterInitialization(), then return bean.
- if return null, go on
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
-
do create bean
-
create instance
真正的實例化, 調用 mbd 中定義的 factoryMethod, 或者類的構造方法, 來生成對象.
-
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition // 比如autowire等 注解注入 mbd
對 mbd 進行初始化前的操作, 比如掃描 class 定義, 找到 @autowired 注解來生成注入信息存放在 mbd 中.
-
add early singleton cache
這一步主要是為了解決循環(huán)引用, 再把未初始化的 bean 的 reference 提供出來.
-
populate bean
填充屬性階段, properties values (pvs), 這一大步驟中的前三小步都是在構造 pvs, 并在最后一步 apply 進去
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
-
autowire
把能夠 set 的的屬性寫入 pvs
-
InstantiationAwareBeanPostProcessor.postProcessPropertyValues()
把一些特殊屬性寫入, 比如沒有 set 的 autowired 屬性, 一些 @Value 的屬性
apply property values
-
initialize bean
實例化完畢之后, 進行初始化.
-
aware beanName, classLoader, beanFactory
如果有需要, 把這三個特殊的對象放到 bean 里
BeanPostProcessor.postProcessBeforeInitialization()
-
init
真正的初始化操作
- 如果 bean 是 InitializingBean, afterPropertiesSet()
- 調用自定義 init
BeanPostProcessor.postProcessAfterInitialization()
-
register disposable bean
-
-
我們在這個過程中能做的
-
InstantiationAwareBeanPostProcessor
實現(xiàn)這個接口的類, 可以在類的實例化階段, 做一些操作.
這個接口有三個方法:
-
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
在實例化之前進行一些操作, 目的是提供一個機會由這個方法來實例化對象. 比如 proxy, mock
-
boolean postProcessAfterInstantiation(Object bean, String beanName)
bean set屬性前執(zhí)行, 如果返回false, 將會跳過屬性處理. 這個一般都是返回true.
-
PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
屬性構造完成, apply 到對象前執(zhí)行, 傳入 pvs 并返回 pvs, 有機會對 pvs 進行處理. 比如 required 檢測在這一步.
-
-
BeanPostProcessor
這個接口有兩個方法:
-
Object postProcessBeforeInitialization(Object bean, String beanName)
在初始化之前 傳入 bean 并返回 bean, 但返回的 bean 可以被包裝或者替換
-
Object postProcessAfterInitialization(Object bean, String beanName)
同上, 也可以做一些 bean 初始化完成后的回調. 比如可以監(jiān)聽每一個 bean 的初始化時機.
-
交流
歡迎加入群 661035226速兔,gradle贩毕,spring亏镰,activiti 交流