做一個合格的程式猿之淺析Spring IoC原始碼(十一)Spring refresh()方法解析之一
經過上面幾節的簡單介紹我們瞭解了spring的一些元件,現在我們來分析一下AbstractApplicationContext中的refresh()這個核心方法吧~
用我們上一節的程式碼,debug進入refresh方法:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 準備beanfactory來使用這個上下文.做一些準備工作,例如classloader,beanfactoryPostProcessor等 prepareBeanFactory(beanFactory); try { //允許上下文的子類去執行postProcessor postProcessBeanFactory(beanFactory); // 開始執行註冊到該上下文的BeanFactoryPostProcessors invokeBeanFactoryPostProcessors(beanFactory); // 開始註冊BeanPostProcessor來攔截其他的bean的初始化過程 registerBeanPostProcessors(beanFactory); // 初始化訊息源 initMessageSource(); //註冊上下文事件的廣播集 initApplicationEventMulticaster(); //初始化一些特殊的bean onRefresh(); //查詢並校驗監聽器並註冊 registerListeners(); // 例項化所有非懶載入的所有bean finishBeanFactoryInitialization(beanFactory); //最後一步釋出所有的運用 finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
結合上一節我們給出的spring的一些元件例項化的初始化順序圖:
我們先看invokeBeanFactoryPostProcessors(beanFactory)這個方法
<span style="color:#000000;">protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 先執行BeanDefinitionRegistryPostProcessors,因為我們這邊沒有實現這個介面,先暫時忽略,這段程式碼 Set<String> processedBeans = new HashSet<String>(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>(); List<BeanDefinitionRegistryPostProcessor> registryPostProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>(); for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryPostProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryPostProcessor.postProcessBeanDefinitionRegistry(registry); registryPostProcessors.add(registryPostProcessor); } else { regularPostProcessors.add(postProcessor); } } Map<String, BeanDefinitionRegistryPostProcessor> beanMap = beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false); List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans = new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values()); OrderComparator.sort(registryPostProcessorBeans); for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) { postProcessor.postProcessBeanDefinitionRegistry(registry); } invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(registryPostProcessorBeans, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); processedBeans.addAll(beanMap.keySet()); } else { // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory); } //在beanFactory中獲取實現BeanFactoryPostProcessor這個介面的bean的名稱 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // 將獲取到的BeanFactoryPostProcessors的bean分類,根據這些bean是否也實現了PriorityOrdered,Ordered這些介面,或者其他,因為我們的例子中 // 並沒有實現這些介面,所以我們的"springMultiBean"這個在spring-init.xml中(程式碼見上一節)定義的bean將進入nonOrderedPostProcessorNames.add(ppName)這個程式碼塊 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)) { // skip - already processed in first phase above } else if (isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } //首先先執行實現“權重排序”的BeanFactoryPostProcessors,我們的bean“springMultiBean”並沒有實現,所以不管 OrderComparator.sort(priorityOrderedPostProcessors); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // 然後執行實現“排序”的介面的BeanFactoryPostProcessors,我們也沒有實現,暫時不看這塊程式碼塊 List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class)); } OrderComparator.sort(orderedPostProcessors); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // 最後執行“其他”的BeanFactoryPostProcessors,這邊就即將執行我們的springMultiBean這個bean的BeanFactoryPostProcessors // 這邊新建了一個List型別是BeanFactoryPostProcessor,好了,這邊就開始需要例項化實現BeanFactoryPostProcessor的bean了,否則, // 無法放入List<BeanFactoryPostProcessor> 也就是說,如果想先執行BeanFactoryPostProcessor的方法,必須先例項化實現該介面的bean List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); //可能我們的配置檔案有很多的bean實現了BeanFactoryPostProcessors,迴圈bean的名字 for (String postProcessorName : nonOrderedPostProcessorNames) { //底下的方法塊是核心塊,getBean這個方法就是初始化實現BeanFactoryPostProcessor這個介面的bean了,例項化好了之後放入List<BeanFactoryPostProcessor> nonOrderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class)); } //批量執行nonOrderedPostProcessors中的BeanFactoryPostProcessor invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); }</span>
好了,到目前為止,我們應該知道了上一節的spring Bean例項化順序的執行截圖了:
也就是我們的上次總結的結論:
①首先執行的是建構函式
②然後執行的BeanNameAware這個介面中的方法
③然後執行的是BeanFactoryAware這個介面中的方法
④執行InitializingBean介面中的afterPropertiesSet的方法
⑤執行我們在xml中定義的init-method這個方法
⑥最後執行的是BeanFactoryPostProcessor這個方法
分析了invokeBeanFactoryPostProcessors這個方法,我們知道這個方法就是去執行BeanFactoryPostProcessor
我們接著分析一下getBean這個超級核心的方法:
<span style="color:#000000;">@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
</span>
好吧~,這個getBean的具體實現貌似有點長,一步步分析吧
第一部分:
這個方法首先先去singleton快取中去找例項(這裡我們肯定沒找到,應該我們沒有把我們的bean手動放入singletonObjects這個Map裡面去)
第二部分:
這段程式碼是先獲取該beanFactory父factory,希望從這些factory中獲取,如果該beanfactory有父類,則希望用父類去例項化該bean,我們這邊的beanfactory為null,暫不討論~
接著看第三部分:
上圖中
第一部分先標記目前的bean的正在建立
第二部分獲取根據beanName該bean在beanfactory中的beanDefinitionMap的BeanDefinition,然後去獲取這個bean依賴的bean,如果依賴的bean還沒有建立,則先建立依賴的bean,遞迴呼叫,(Dependence Inject依賴注入的概念吧),如果找不到依賴,則忽略
第三部分:如果是單例(我們暫時只討論如何建立單例)
則呼叫createBean()這個方法
好了,我們暫不看Prototype建立的過程,我們接著跟蹤createBean()
上圖中
第①部分:確保該bean的class是真實存在的,也就是該bean是可以classload可以找到載入的
第②部分:準備方法的重寫
第③部分(很重要):請注意,這邊有個return,也就是說這邊可以返回bean了,但看註釋:Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.這邊就很清晰了,我們以前在beanPostProcessor的章節講過,beanPostProcessor是可以臨時修改bean的,它的優先順序高於正常例項化bean的(也就是第四部分例項化的方法),如果beanPostProcessor能返回,則直接返回了,這邊程式碼下次分析,我們還是先分析主要流程:
看第四部分:
doCreateBean(beanName, mbd, args)這個方法
這個方法首先初始化一個BeanWrapper,然後再看createBeanInstance()
這塊程式碼主要是再次對bean做安全檢查並確定該bean有預設的建構函式,createBeanInstance()這個方法最後一行
此時建構函式列印了我們system的內容,也就是第一個列印的
回到doCreateBean()這個方法
初始化bean,的確,現在bean已經例項化了,開始初始化該bean,進入initializeBean(...)這個方法
執行aware方法(看來beanFactoryAware和beanNameAware要執行了)
看原始碼果然:
接著
開始執行初始化方法
首先先判斷該bean是否實現了InitializingBean,如果實現了先執行afterPropertiesSet這個方法,然後如果該bean又執行了init-method,事實的確如此:
好了,到此為止,我們的第一個名為“springMultiBean"已經初始化了,例項化好的大體步驟我們已經基本瞭解了,大家先體會一下,我們spring-init.xml中還有一個bean”springOtherBean“沒講解,下次分解~正好一起重新分析細節~
相關推薦
做一個合格的程式猿之淺析Spring IoC原始碼(十一)Spring refresh()方法解析後記1
上次分析refresh這塊spring IoC的時候,時間比較倉促,只是debug了部分原始碼,大家分析起來不是很好~ 今天我們還是先總結一下吧~ spring在例項化bean的時候,根據bean
做一個合格的程式猿之淺析Spring IoC原始碼(十一)Spring refresh()方法解析之一
經過上面幾節的簡單介紹我們瞭解了spring的一些元件,現在我們來分析一下AbstractApplicationContext中的refresh()這個核心方法吧~ 用我們上一節的程式碼,debug進入refresh方法: public void refresh() th
Spring 原始碼(十一)Spring流程彙總
Spring 容器初始化流程大致流程如下: this():註冊內建的BeanPostProcessor的BeanDefinition到容器 register(annotatedClasses):註冊配置類 BeanDefinition 到容器 prepareRefresh():初始化前的準備工作,列如對系
做一個合格的程式猿之淺析Spring IoC原始碼(十)Spring Bean的初始化順序
上幾節我們比較詳細地說明了一下BeanFactoryPostProcessor和BeanPostProcessor這2個介面的作用和意義,並且也花了一個章節,講了一下BeanFactory和FactoryBean的關係,最後我們也稍微說明了一下BeanFactoryAwar
做一個合格的程式猿之淺析Spring AOP原始碼(十五) 分析JdkDynamicAopProxy的invoke方法
上一節我們已經分析了Proxyfactorybean如何去生成一個目標物件的代理的,這一節我們將淺析一下基於JDK動態代理的核心回撥方法invoke的原始碼: 首先先開啟JdkDynamicAop
Spring(十一)Spring事物
一個 簡單介紹 數據 數據庫操作 nag 原子性 pre spring pointcut 事務是訪問數據庫的一個操作序列,DB應用系統通過事務集來完成對數據的存取。 事務必須遵循4個原則,即常說的 ACID A,Automicity,原子性,即事務要麽被全部執行
機器學習之numpy和matplotlib學習(十一)
今天繼續來學習numpy。 學習有關複數矩陣在numpy中的建立和使用。 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : SundayCoder-俊勇 # @File : numpy3.py import
機器學習之python入門指南(十一)numpy常用方法簡介
numpy庫的安裝: window下命令列直接輸入pip install numpy 匯入numpy庫:import numpy 或者 import numpy as np numpy與list: 相同之處: 都可以用下標訪問元素,如a[3]. 都可以
各種音視訊編解碼學習詳解之 編解碼學習筆記(十一):Flash Video系列
最近在研究音視訊編解碼這一塊兒,看到@bitbit大神寫的【各種音視訊編解碼學習詳解】這篇文章,非常感謝,佩服的五體投地。奈何大神這邊文章太長,在這裡我把它分解成很多小的篇幅,方便閱讀。大神部落格傳送門:https://www.cnblogs.com/skyofbitbit/p/3651
Spring Security原始碼分析十一:Spring Security OAuth2整合JWT
Json web token (JWT), 是為了在網路應用環境間傳遞宣告而執行的一種基於JSON的開放標準(RFC 7519).該token被設計為緊湊且安全的,特別適用於分散式站點的單點登入(SSO)場景。JWT的宣告一般被用來在身份提供者和服務提供者
(十一)Spring事務處理
Spring的宣告式事務處理的即開即用特性為使用者提供了很大的方便,在使用Spring時,我們絕大多數情況下還是使用其宣告式事務處理。宣告式事務處理涉及Spring框架對事務處理的統一管理,以及對併發事務和事務屬性的處理,是一個比較複雜的過程,下面瞭解一
Spring Boot:(十二)Spring Boot使用單元測試
前言這次來介紹下Spring Boot中對單元測試的整合使用,本篇會通過以下4點來介紹,基本滿足日常需求Service層單元測試Controller層單元測試新斷言assertThat使用單元測試的回滾正文Spring Boot中引入單元測試很簡單,依賴如下:1 2 3 4
Spring學習筆記(十一)AOP的註解方式cglib代理
JDK動態代理與CGLib動態代理均是實現Spring AOP的基礎,切點,切面,如何定義切點,前置、後置、放回、異常、環繞通知 1.切點、切面 紅色的地方就是切面,增加額外的功能 連線點+增加功能的位置 = 切點 2.專案結構
spring學習(十一)——spring官方文件閱讀(5.0.7)——spring的@Bean與@Configuration註解
@Bean與@Configuration註解 @Bean註解用於方法上,返回的例項將由Spring IOC管理,當在@Configuration註解的類中使用@Bean註解時,@Bean相當於<bean/>元素,@Configuration相當於<bean
HBase 系列(十一)—— Spring/Spring Boot + Mybatis + Phoenix 整合
一、前言 使用 Spring+Mybatis 操作 Phoenix 和操作其他的關係型資料庫(如 Mysql,Oracle)在配置上是基本相同的,下面會分別給出 Spring/Spring Boot 整合步驟,完整程式碼見本倉庫: Spring + Mybatis + Phoenix SpringBoot
Spring Boot 入門(十一):整合 WebSocket, 實時顯示系統日誌
以前面的部落格為基礎,最近一篇為Spring Boot 入門(十):整合Redis哨兵模式,實現Mybatis二級快取。本篇部落格主要介紹了Spring Boot整合 Web Socket進行日誌的推送,並實時顯示在頁面上。 1.匯入jar包 第一個jar包是websocket的,第二個jar包是關於環形佇列
spring-boot-route(十一)資料庫配置資訊加密
Spring Boot最大的特點就是自動配置了,大大的減少了傳統Spring框架的繁瑣配置,通過幾行簡單的配置就可以完成其他元件的接入。比如你想要連線mysql資料庫,只需要的配置檔案裡面加入mysql的一些配置資訊就可以了。為了保護資料的安全性,越來越多的公司選擇加密這些重要資訊。接下來一起來看看如何實現配
spring-boot-route(十九)spring-boot-admin監控服務
`SpringBootAdmin`不是Spring官方提供的模組,它包含了`Client`和`Server`兩部分。server部分提供了使用者管理介面,client即為被監控的服務。client需要註冊到server端。 SpringBootAdmin提供了很少的幾個監控服務端點,需要依賴SpringBo
程式猿之---C語言細節9(巨集定義、max(a,b)巨集定義細節、大小端判斷、(int&)a什麼意思)
主要內容:巨集定義、max(a,b)巨集定義細節、大小端判斷、(int&)a什麼意思 #if 1 #include <stdio.h> // 注意空格 #define F (x) ((x) - 1) // F代表後面 #define F(x)
十年風雨,一個普通程式設計師的成長之路(十一)再見,2019。你好,2020!
00 回顧2019 在過去的這一年裡,收穫最大的便是眼界了, 與高水平的同事們一起合作,讓人愉快。 與高水平的領導共事,則讓人受益匪淺。 2019年元旦前後那段時間,突然陷入了焦慮,買了一些極客時間的課程,加入了一些知識星球。也確實提升了自己不少關於職場、工作、生活的一些認知。 但是收貨最大的還是在工作之餘,