白話文剖析[spring4.2.1.RELEASE] IOC核心架構
在這篇文章中,我將用第一人稱的方式向你闡述spring4.2.1.RELEASE IOC部分的基本架構,你可以用如下的簡單demo開啟原始碼debug之旅
demo包含三個檔案
User.java
public class User {
@Override
public String toString() {
return "hi, I am a user!";
}
}
user.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="ch0.User"/>
</beans>
UserTest.java
public class UserTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ch0/user.xml");
User user = context.getBean(User.class);
System.out.println(user);
}
}
UserTest.java
中通過ClassPathXmlApplicationContext 建立了一個上下文,xml檔案在類路徑下,然後通過getBean
的方式可以拿到該bean
我們直接進到new ClassPathXmlApplicationContext(“ch0/user.xml”); 看看我到底做了什麼事情~_~
ClassPathXmlApplicationContext.java
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
呼叫
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 層層呼叫父類建構函式, 最終只是為了獲取ResourcePatternResolver, 我需要這玩意是因為我
// 要將你傳給我的配置檔案("ch0/user.xml")這個引數轉換為我內部可以處理的資源抽象 Resource
super(parent);
// 你可以不用告訴我非常精確的配置檔案, 可以寫佔位符。在這個函式裡面,我可以解析出完整的配置檔案路徑
setConfigLocations(configLocations);
// 基本都需要重新整理的啦(refresh == true),在重新整理上下文的時候,我會用你給我的配置檔案完成幾乎所有的事情哦
if (refresh) {
refresh();
}
}
上面的函式先呼叫super(parent)
層層往上呼叫,最終發現做了這麼一件事情
AbstractApplicationContext.java
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
resourcePatternResolver
這從字面上就可以知道這傢伙是做資源解析的用的呢,檢視一下ResourcePatternResolver
的定義,發現重點只有這麼一行
ResourcePatternResolver.java
Resource[] getResources(String locationPattern) throws IOException;
這裡的 locationPattern
代表實際的資源路徑(基本上就等同於xml檔案路徑啦),這傢伙可以把一個資源路徑轉換為描述資源的抽象Resource
, 好了,初次看spring原始碼瞭解到這裡就夠了,關於 Resource
的深入裡面後面會後專題分析!
繼續下面一行
setConfigLocations(configLocations);
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
這一句的作用就是將建立ApplicationContext傳入進來的ch0/user.xml
轉換為合法的location,將location裡面類似${key}
的placeHolder 轉換為實際的值
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
而轉換過程中會通過getEnviroment()
拿到ConfigurableEnvironment
物件來進行佔位符${}的替換,標準的Enviroment
物件為
StandardEnvironment.java
public class StandardEnvironment extends AbstractEnvironment {
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}
可以看到在設定替換placeHolder的源的時候,最終會通過getProperties()
,和System.getenv()
來獲取啟動jvm的時候的環境變數和系統環境變數,也就是說,如果你傳入的location裡面有個${key}
佔位,而jvm引數或者系統環境變數裡面剛好有個變數叫做key
那麼spring在解析該location的時候,會將該佔位解析為對應的value
接下來,到了
if (refresh) {
refresh();
}
這一行可是我的重頭戲啊,我的核心功能都在這個refresh()
方法裡面搞定哦
在我們這個demo中,refresh
引數為true,所以,直接進入到refresh()
方法,激動人心的時刻終於到來,go!
AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 重新整理工廠之前需要做一些準備工作的啦,就想你在運動之前要做一些準備運動一樣哦
prepareRefresh();
// 我會告訴我的子類創造一個工廠,來把我需要建立bean的原料BeanDefinition準備好
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 原料準備好之後呢,我要宣告一些特殊的依賴關係, 所謂依賴,就是我在創造一個bean A的時候,發現它裡面有另外一個屬性B
// 那麼B就是A的依賴,我在創造A的時候,必須先把B創造好,特殊關係的依賴就是指我遇到B的型別,我該放棄呢,還是告訴他直接用
// 現成的(也就是不用再去創造B了)
prepareBeanFactory(beanFactory);
try {
// 這裡沒啥,就是留給子類做擴充套件的啦
postProcessBeanFactory(beanFactory);
// 到了這裡,工廠已經準備好了,如果你之前告訴過我工廠準備好之後應該幹什麼事情,這邊我就可以滿足你的需求哦
// 不信,你去看看BeanFactoryPostProcessors介面是幹嘛用的吧==
invokeBeanFactoryPostProcessors(beanFactory);
// 在建立一個bean的前後,我也留給你很多擴充套件,原理上和上面的工廠擴充套件差不多的哦
registerBeanPostProcessors(beanFactory);
// 就是處理一些國際化的操作啦,啊?什麼是國際化,就是i18n啦,還不懂?你沒救了
initMessageSource();
// 我的功能很豐富,除了可以給你建立bean,還可以有事件管理的功能哦,這裡我就建立一個管理器(ApplicationEventMulticaster(),
// 用來註冊事件(ApplicationEvent)
// 我會將這些事件廣播給合適的監聽者(ApplicationListener)那邊哦
initApplicationEventMulticaster();
// 啥也不幹,留給子類擴充套件啦
onRefresh();
// 前面不是事件管理器搞好了嘛,這邊呢,就是把那些事件監聽器給註冊進來啦,這樣來一個新的事件我就知道該發給誰啦
registerListeners();
// 如果某些bean告我我,他想在我工廠建立之初就想初始化(一般要是單件singleton並且lazy-init為false),那麼我在這個函式會滿足他
finishBeanFactoryInitialization(beanFactory);
// 終於重新整理完了,我要開始釋出事件了!
finishRefresh();
}
// 什麼?重新整理的時候報錯了?oh my god,我需要做一些清理
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// 我需要將我建立的bean銷燬掉
destroyBeans();
// 我不再活躍
cancelRefresh(ex);
// 我要告訴你,我出異常了,救我!!
throw ex;
}
finally {
// 一些通用的快取清掉!!
resetCommonCaches();
}
}
}
下面, 我來告訴你每個函式我到底做了哪些見不得人的事==, ready?go!!
prepareRefresh();
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 初始化佔位符placeHolder源頭
initPropertySources();
// 驗證一些必要屬性, 當然這些必要屬性是你告訴我的哦
getEnvironment().validateRequiredProperties();
// 誒呀,我在重新整理的時候事件管理器還沒做好呢,我得先建立一個臨時的池子,好讓在沒建立事件管理器之前將需要釋出的事件存起來啊!
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
好的,到了這裡我要開始重新整理整個ApplicationContext了。
- 首先,我會記錄下重新整理時間,將ApplicationContext標誌為活躍狀態
- 然後,我在解析配置檔案中的placeHolder的時候,會需要一些資源,所以,我會初始化
PropertySources
, 該函式預設為空實現protected,表明是留給子類實現的,比如web裡面的上下文什麼的 - 接下來,我要驗證一下我需要的一些必要屬性有沒有設定,如果沒有設定,我是不會讓你繼續下去的,直接拋個
MissingRequiredPropertiesException
異常給你玩 - 最後,我將初始化一下我接受事件的載體
earlyApplicationEvents
,這玩意裡面將儲存所有的通過AbstractApplicationContext: publishEvent(ApplicationEvent event)
來publish的事件
到了這裡,我準備重新整理的工作做完了,這邊真的開始重新整理了哦
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷啊刷
refreshBeanFactory();
// 刷完了,可以出鍋了
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
我重新整理完工廠,然後將工廠返回,跟我走, 看看在refreshBeanFactory()
裡面做了哪些事情
AbstractRefreshableApplicationContext.java
protected final void refreshBeanFactory() throws BeansException {
// 什麼?我之前建立過工廠?銷燬掉產品,關掉它!
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 開始創辦工廠!
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 給工廠取個名字唄
beanFactory.setSerializationId(getId());
// 來,給你特殊定製一下
customizeBeanFactory(beanFactory);
// 載入建立產品(bean)需要的原料(beanDefinition)
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
- 首先,我會檢查一下我之前有木有建立過Bean工廠,如果建立過,那麼我要先將ta銷燬,銷燬的意思嘛,就是將我bean工廠裡面的所有的單例bean全清除掉哦,然後將工廠關閉,就是把我的bean工廠的名字也抹掉啦
- 然後,我要開始建立新的bean工廠了,第7行中,我要先把廠子搭建好,這樣,才能容得下之後的bean啊,這裡偷偷告訴大家,這裡創建出來的
DefaultListableBeanFactory
可是重量級嘉賓,你用到的許許多多的bean什麼的都是這傢伙搞出來的呢 - 接下來呢,我就給工廠取個好聽的名字,然後將你告訴我的兩樣重要的事情轉達給bean工廠
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
這兩件重要的事情就是,該工廠是否可以支援Bean定義的覆蓋,即是否可以在不同的配置檔案裡面定義兩個相同名字的的bean;是否支援迴圈引用,迴圈引用的意思是A依賴B,B依賴C,結果又發現C依賴A,那就說明A產生了迴圈依賴,我在解決迴圈依賴這方面可是很牛逼的,以後有時間我會慢慢向你訴說。
4. 最後,我就開始裝載bean原料(BeanDefinition)了,在這裡提一下,很重要的哦,我在建立每個bean的時候,會先將所有bean的原料選準備好,包括bean裡面所有屬性的描述,構造防範的描述,依賴關係的描述,我都給抽象好,以便之後我建立bean的時候直接拿來用
loadBeanDefinitions(beanFactory);
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 創造一個xml讀取器,為我的工廠讀取配置
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
裝載bean原料(BeanDefinition)的時候,我要先創造一個讀取器(BeanDefinitionReader)來幫載入資源(Resource),大多數情況下,我一般用xml讀取器(XmlBeanDefinitionReader)來讀取資源。建立好了資源讀取器之後,給這個資源讀取器設定一些環境啦(Environment),資源載入器啦(ResourceLoader, 為了讓資源讀取器在讀取到import之類引入其他資源的時候可以通過location轉換為Resource),還有讀取xml的一些輔助(EntityResolver),最終會進入到
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
reader可以根據Resource來載入bean原料,也可以根據location來載入bean原料(想想為什麼,上面我告訴過你的哦),好了,再跟下去估計你要暈了,就到這裡了,總結一下,獲取bean 工廠就是先搭一個廠子,然後通過bean原料讀取器將bean原料載入到bean工廠裡面,有了這個bean原料,後面我可以做很多很多事情。
我們繼續回到牛逼哄哄的refresh方法,到了下面這一行, 函式體過於龐大,但都是紙老虎,不要怕!
prepareBeanFactory(beanFactory);
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 我需要只要我在創造bean的時候用啥來載入
beanFactory.setBeanClassLoader(getClassLoader());
// 我還有el表示式(#{})的功能哦,這裡就詳細說el是啥玩意啦,自己百度哦
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 屬性轉換器註冊中心,用來註冊屬性轉換器,比如'1989-07-30'轉換為Date型別啦,你得告訴我怎麼轉換才行呀
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 特殊的bean後置處理器,用來在bean初始化前後做一些手腳,這個ApplicationContextAwareProcessor
// 的主要作用就是給實現了某些特殊介面的bean注入一些特殊的bean
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 忽略的依賴
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
// 特殊的依賴規則
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// AOP相關的一些東西,可以先不用關注
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注入環境相關的一些bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
- 設定類載入器,用於之後bean原料的加工製作
- 設定el表示式(類似#{key})解析器
- 設定屬性編輯器註冊中心,屬性編輯器這玩意主要用於屬性從一種形式轉換成另外一種形式,比如從
‘2015-11-26 21:29:11’轉換成為一個合法的java.util.Date
型別,我內建了很多屬性編輯器哦 - 注入Bean後置處理器(BeanPostProcessor), 關於BeanPostProcessor的具體用法後面會具體描述,這裡簡單提一下哦,這個
BeanPostProcessor
在Bean例項化之前之後可以做一些定製化的操作,從字面意思上來看,ApplicationContextAwareProcessor
要做的事情就是給實現了與ApplicationContext相關介面的bean注入一下上下文資訊,比如環境呀,工廠呀,上下文呀什麼的 - 下面這五行我會告訴bean工廠,你在解決bean的依賴關係的時候,如果碰到了
ResourceLoaderAware
,ApplicationEventPublisherAware
,MessageSourceAware
,ApplicationContextAware
,EnvironmentAware
就不要試圖取獲取這些bean啦,直接忽略掉就行了 - 上面我告訴bean工廠忽略掉一些bean依賴的注入,下面我同樣會告訴bean工廠,你在解決下面幾個依賴的時候,直接把我告訴你的bean拿去用就行啦,這些bean都是與上下文相關的
BeanFactory
,ResourceLoader
,ApplicationEventPublisher
,ApplicationContext
, 猜一下,為啥第二個引數中有this?那就說明我(作為ApplicationContext)同時具有這三者的功能啦,是時候告訴你我是誰了!後面幾行也就是註冊了幾個單例,載入環境資訊啦,沒啥好說的。好,放大招,看看我是誰啦
我又可以釋出事件ApplicationEventPublisher
, 又可以通過檔案路徑解析資源ResourcePatternResolver
, 還可以處理國際化MessageSource
, 還可以建立bean,獲取beanListableBeanFactory
,並且我可以告訴你我的父工廠是誰HierarchicalBeanFactory
, 甚至可以告訴你我現在處在什麼環境中EnvironmentCapable
,好啦,我是不是很牛逼,算了,低調,低調,哈哈哈
可以看到,我內部的物件管理也是通過註冊bean來實現的哦,和你定義的bean沒啥本質區別啦
暈啊暈,趕緊回憶一下我們到講到哪一行了,快看,還是在refresh方法裡面沒出來啊==
postProcessBeanFactory(beanFactory);
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
是的,你沒看錯,這行裡面啥都沒,但是,仔細看哦,這個是protected
方法,你懂的,我可以留給我的子類來擴充套件這個方法做一些更牛逼的事情
轉啊轉,轉到下面這一行,這一行告訴你,我的工廠中製作bean的原料(BeanDefinition)準備好了, 準備好之後,我可以給你一個機會更改這些原料,你通過向我註冊BeanFactoryPostProcessor就可以達到你不可告人的祕密, 在這裡,你可以做任何事情,甚至將我的工廠炸燬掉也行啊(搞壞所有的原料)
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
好了,還是看看我是怎麼呼叫你給我註冊的這些後置處理器的吧
invokeBeanFactoryPostProcessors(beanFactory);
呼叫
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}
繼續轉啊轉轉到這個類
PostProcessorRegistrationDelegate.java
這個類是在2013-8-28,Juergen Hoeller 這傢伙重構過的, since spring 4.0,主要處理一些後置處理器相關的複雜的操作,由於函式體過於龐大,這裡我就帶你深入到內部去剖析,帶你裝逼帶你飛
首先,我簡要的告訴你這段程式碼做了什麼事情,看到傳入的beanFactoryPostProcessors
引數沒有,所有的beanFactoryPostProcessor
中,他們是最先被執行的哦,他們是通過呼叫
AbstractApplicationContext
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
}
加入到成員變數 beanFactoryPostProcessors
, 然後通過
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
傳到這裡來的
這裡的 BeanFactoryPostProcessors
可以分為兩種,一種是非常普通的,一種是BeanDefinitionRegistryPostProcessor
, 字面上意思也可以看的出來,這玩意功能更多呀,
主要多了 postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
這麼一個方法, 基本上可以猜出來這個方法是給你註冊bean原料(beanDefinition用的哦)
下面的呼叫比較複雜,我大概和你先講下做了什麼事情
首先呢,check一下我這個工廠是否有註冊bean原料的能力(beanFactory instanceof BeanDefinitionRegistry)
)
如果有的話:
先處理通過addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor)
註冊進來的beanFactoryPostProcessors
處理的時候
如果該後置處理器是 BeanDefinitionRegistryPostProcessor
, 先呼叫它的postProcessBeanDefinitionRegistry
方法,由於它又是一個BeanFactoryPostProcessor
所以要將它榨乾registryPostProcessors.add(registryPostProcessor);
, 以便接下來再呼叫它的postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
的功能
如果是普通的beanFactoryPostProcessors, 保留起來, 然後,按照如下優先順序依次呼叫
1. 實現了PriorityOrdered介面(呼叫之前先排序)
2. 實現了Ordered介面(呼叫之前先排序)
3. 普通的BeanDefinitionRegistryPostProcessor
最後,再次呼叫BeanDefinitionRegistryPostProcessor繼承下來的BeanFactoryPostProcessor
的功能,以及普通的beanFactoryPostProcessors
如果這個工廠沒有註冊bean原料的能力,那麼說明後置處理器中不存在BeanDefinitionRegistryPostProcessor, 就直接將你通過addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor)
註冊進來的beanFactoryPostProcess執行一遍啦
好了,上面是處理通過addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor)
註冊進來的beanFactoryPostProcess
以及BeanDefinitionRegistryPostProcessor
, 接下來便是處理普通的BeanFactoryPostProcessor
了
這邊處理流程就比較簡單了,處理順序為
1. 實現了PriorityOrdered介面(呼叫之前先排序)
2. 實現了Ordered介面(呼叫之前先排序)
3. 普通的BeanFactoryPostProcessor
下面,我帶著你分析每一行程式碼
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 用於記錄處理過的beanFactoryPostProcessors,最簡單的防止重複處理的辦法就是處理完扔到這裡面然後每次處理之前看看這裡面有沒有,有就不處理
Set<String> processedBeans = new HashSet<String>();
// 如果實現了BeanDefinitionRegistry介面, 那就需要處理BeanDefinitionRegistryPostProcessor, 因為BeanDefinitionRegistryPostProcessor
// 主要就是用來註冊BeanDefinitionRegistry的
if (beanFactory instanceof BeanDefinitionRegistry) {
// 強制轉換一下,以便當引數傳給 BeanDefinitionRegistryPostProcessor的 postProcessBeanDefinitionRegistry的方法
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 記錄普通的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
// 記錄處理過的BeanDefinitionRegistryPostProcessor, 主要是為了之後呼叫它繼承自BeanFactoryPostProcessor的
// postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,
List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
new LinkedList<BeanDefinitionRegistryPostProcessor>();
/**
* BeanDefinitionRegistryPostProcessor 在任何常規的postProcessor之前執行
*/
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryPostProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
// 處理完之後要榨乾它哦
registryPostProcessors.add(registryPostProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// 獲取使用者通過非api的方式註冊的BeanDefinitionRegistryPostProcessor, 非api的意思就是在xml獲取通過註解的方式
// 向我隱式註冊, 比如你定義一個類實現了BeanDefinitionRegistryPostProcessor介面,並且這個類對應的bean被我管理,我
// 在這裡就可以拿到
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 記錄實現了PriorityOrdered介面的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 要記錄一下,這個BeanDefinitionRegistryPostProcessor已經被處理完了哦
processedBeans.add(ppName);
}
}
// 按照getOrder返回的整數從小到大排序,最小的先執行
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 榨取,繼續榨取
registryPostProcessors.addAll(priorityOrderedPostProcessors);
// 好了,終於可以執行了
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
// 記錄實現了Ordered介面的BeanDefinitionRegistryPostProcessor
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
// 處理之前呢,要看下這個BeanDefinitionRegistryPostProcessor之前有木有處理過哦
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 按照getOrder返回的整數從小到大排序,最小的先執行
sortPostProcessors(beanFactory, orderedPostProcessors);
// 榨取,繼續榨取
registryPostProcessors.addAll(orderedPostProcessors);
// 好了,終於可以執行了
invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);
// 最後呢,處理常規的BeanDefinitionRegistryPostProcessor
// 等等,這裡為毛這麼複雜,還有while迴圈啊!!!請記住BeanDefinitionRegistryPostProcessor可以幹些什麼事情哦
// 它可以向我註冊bean,萬一某個BeanDefinitionRegistryPostProcessor(假設叫A)向我註冊的bean的是BeanDefinitionRegistryPostProcessor型別的bean呢(假設為B),按照
// 約定,我也必須搞一遍B啊,那玩意搞B的時候,這個B又向我註冊了一個C,按照約定,我必須要再搞一遍C啊,萬一C..
// 所以,這邊就有個迴圈啦,直到我把所有的BeanDefinitionRegistryPostProcessor搞完,就結束啦
/**這裡是為了保證自定義的postProcessBeanDefinationRegistry裡面可能註冊beanPostProcessor**/
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 如果以前處理過就不處理
if (!processedBeans.contains(ppName)) {
BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
// 榨取哦
registryPostProcessors.add(pp);
// 記錄一下我搞過這個傢伙
processedBeans.add(ppName);
// 搞之
pp.postProcessBeanDefinitionRegistry(registry);
// 搞它的時候它又生出來一個,那我就迴圈搞它生出來的
reiterate = true;
}
}
}
// 搞定從BeanDefinitionRegistryPostProcessor搞榨取出來的普通的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
// 搞定BeanFactoryPostProcessor方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 如果該工廠沒有實現了BeanDefinitionRegistry介面,那就不需要處理BeanDefinitionRegistryPostProcessor
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 拿到所有的BeanFactoryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 用三個List記錄三種不同型別的BeanFactoryPostProcessor的bean或者名字
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
nonOrderedPostProcessorNames.add(ppName);
}
}
}
// 執行priorityOrderedPostProcessors之前先排序
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 執行priorityOrderedPostProcessors
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 搞orderedPostProcessors
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(beanFactory, orderedPostProcessors);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 搞普通的BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清除快取資料
beanFactory.clearMetadataCache();
}
整個過程,其實還蠻清晰流暢的嘛
好了,接下來我們看下refresh裡面下一個函式, 同樣又是重量級嘉賓, 但是,當你看懂了beanFactory的後置處理器,來分析這段程式碼,簡直小菜一碟
registerBeanPostProcessors(beanFactory)
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 首先拿到所有的BeanPostProcessor
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 這裡可以不用細看,主要是做postProcessor的check
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 開始分類
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
// 主要儲存MergedBeanDefinitionPostProcessor這以特殊的後置處理器
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 對實現了PriorityOrdered的BeanPostProcessor排序
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 註冊實現了PriorityOrdered的BeanPostProcessor
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 拿到實現了Ordered介面的BeanPostProcessor
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
// 如果這個BeanPostProcessor還實現了BeanPostProcessor介面,保留下來
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// 對實現了PriorityOrdered介面的BeanPostProcessor排序
sortPostProcessors(beanFactory, orderedPostProcessors);
// 註冊實現了PriorityOrdered介面的BeanPostProcessor
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 拿到普通的BeanPostProcessor
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
// 如果這個BeanPostProcessor還實現了MergedBeanDefinitionPostProcessor介面,保留下來
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// 註冊普通的BeanPostProcessor
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 註冊實現了MergedBeanDefinitionPostProcessor的介面,聰明的讀者一定會有疑問,這裡難道不會重複註冊嗎?
// 答案是不會, 因為註冊的時候會先將之前註冊的刪掉的,我這麼做的原因只是為了分類處理而已, 要將所有的
// MergedBeanDefinitionPostProcessor 放到最後處理
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// 最後,添加了一個特殊的後置處理器, 那麼這個後置處理器必然最後一個被處理
// 用來註冊實現了ApplicationListener介面的bean
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
從上面的步驟可以看出和invokeBeanFactoryPostProcessors(beanFactory);
的區別就是這邊只是做一個註冊而已,因為
BeanPostProcessor的功能是在bean初始化前後做一些手腳,那這邊bean還沒初始化呢,呼叫了有個毛用啊?
回到refresh()
繼續下面一行
initMessageSource();
這一行主要是拿到與i18n,即國際化相關的bean, 如果你定義了,我就拿過來註冊上去,如果沒有定義, 那麼我就自己搞出來一個空的,
所有的實現都是繼承自父bean
protected void initMessageSource() {
// 拿到工廠
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// 如果你定義,就拿過來
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// 如果我有父親,並且這個國際化的bean也有層次, 那麼就將我父親的國際化bean設定為這個國際化bean的父親
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// 定義一個空的
DelegatingMessageSource dms = new DelegatingMessageSource();
// 我將我父親的國際化bean拿來作為這個空的國際化bean,這樣所有的國際化操作都通過我父親的國際化bean
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
"': using default [" + this.messageSource + "]");
}
}
}
繼續refresh()
中的下一行
initApplicationEventMulticaster()
註冊事件管理器bean,和上面國際化bean差不多的實現, 如果你註冊了,我就直接拿來用,否則我就自己建立一個預設的
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
refresh()
方法下一行
onRefresh();
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}
裡面啥都沒,又是為了給我子類作為擴充套件!!
繼續refresh()
方法下一行
registerListeners();
就是註冊事件監聽器啦, 也沒啥牛逼的
protected void registerListeners() {
// 先註冊你手工註冊的監聽器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 再註冊在配置檔案或者註解裡面的監聽器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 因為到了這裡,我們終於有了一個事件管理器了,我們早先定義的earlyApplicationEvents
// 可以下崗了,下崗之前,別忘了要把它手中的任務先完成哦
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProces