Spring中的之啟動(dòng)過(guò)程obtainFreshBeanFactory詳解
1.refresh流程
refresh是spring啟動(dòng)的關(guān)鍵方法,refresh啟動(dòng)過(guò)程中,先要得到beanFactory 以及 需要交給beanFactory管理的bean。
在refresh時(shí),prepareRefresh后,馬上就調(diào)用了obtainFreshBeanFactory創(chuàng)建beanFactory以及掃描bean信息(beanDefinition),并通過(guò)BeanDefinitionRegistry注冊(cè)到容器中。
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(); //后面省略 .... } }
2.obtainFreshBeanFactory掃描bean定義信息并注冊(cè)
這里以通過(guò)XML配置spring來(lái)舉例。
- 創(chuàng)建DefaultListableBeanFactory,設(shè)置是否支持beanDefinition重寫(xiě)以及是否支持循環(huán)引用。
- 載入beanDefinition
- 得到所有spring相關(guān)的xml,將其轉(zhuǎn)為Document對(duì)象。
- 解析Document,判斷node是否屬于beans(http://www.springframework.org/schema/beans)這個(gè)命名空間(Namespace)。針對(duì)默認(rèn)命名空間(beans)和非默認(rèn)空間,有不同的處理。
- 處理默認(rèn)命名空間相關(guān)node:import,alias,bean,beans4種node。
- 處理非默認(rèn)命名空間相關(guān)node,如:<context:annotation-config/>、<context:component-scan base-package="xx"/>、<mongo:mongo-client/>
- 注冊(cè)beanDefinition
obtainFreshBeanFactory重要流程
3.必須了解的類
3.1 beanDefinition
包含欲交給spring管理的bean信息 掃描了一個(gè)對(duì)象的信息,包括class,property等。
3.2 NamespaceHandler
注冊(cè)自定義解析類 該接口的作用:注冊(cè)可解析xml中自定義的標(biāo)簽Parser。 實(shí)現(xiàn)類類名與命名空間名字對(duì)應(yīng)。
常見(jiàn)的NamespaceHandler實(shí)例:ContextNamespaceHandler 很明顯能看出有常用的 <context:annotation-config/>、<context:component-scan base-package="xx"/>、<context:property-placeholder/>對(duì)應(yīng)的解析類。
public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }
3.3 BeanDefinitionParser接口
配合DefaultBeanDefinitionDocumentReader去解析xml中自定義的標(biāo)簽。 接口需要實(shí)現(xiàn)BeanDefinition parse(Element element, ParserContext parserContext);方法,該方法返回一個(gè)beanDefination。但是實(shí)際都沒(méi)有處理這個(gè)返回值, 在parse內(nèi)部就解析beanDefination并注冊(cè)到beanDefinationMap中了。 實(shí)現(xiàn)類與節(jié)點(diǎn)名稱對(duì)應(yīng)。
3.4 BeanDefinitionParser與ContextNamespaceHandler的關(guān)系
類似于 xHandler.put(“a”,parserA); Handler.put(“b”,parserB); 當(dāng)處理非默認(rèn)命名空間的節(jié)點(diǎn)時(shí),如x命名空間中的<a>節(jié)點(diǎn),使用xHandler.get(“a”).parse來(lái)解析并注冊(cè)beanDefinition
4.處理默認(rèn)命名空間
以處理<bean>為例,調(diào)用裝飾器去解析delegate.parseBeanDefinitionElement(ele)將bean上的屬性,如id,name,property,class等,并返回一個(gè)BeanDefinition對(duì)象。然后調(diào)用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())將其注冊(cè)到beanDefinitionMap中。
5.處理非默認(rèn)命名空間
根據(jù)命名空間得到對(duì)應(yīng)的NamespaceHandler,然后調(diào)用節(jié)點(diǎn)對(duì)應(yīng)的parser去解析注冊(cè)beanDefinition.
如context命名空間中解析<context:component-scan base-package="com.gkwind.xxx"/>的ComponentScanBeanDefinitionParser
這里解析有點(diǎn)復(fù)雜,但思路很簡(jiǎn)單: 從xml文件對(duì)應(yīng)的element中處理對(duì)應(yīng)的node。將node的屬性裝配成beanDefinition或者利用其屬性代表的特殊含義去注冊(cè)beanDefinition. 如這里<context:component-scan base-package="com.gkwind.xxx"/>),就表明需要:
1.掃描這個(gè)包下面的所有class。
2.將符合filter的class包裝為beanDefinition并注冊(cè)到beanDefinitionMap中。
如:含有@Component等注解的class
6.debug的時(shí)候遇到的問(wèn)題
DefaultNamespaceHandlerResolver的toString方法會(huì)觸發(fā)getHandlerMappings,而使用idea debug的時(shí)候會(huì)調(diào)用toString引起handlerMapping初始化,導(dǎo)致看到handlerMapping莫名的出現(xiàn)值。
@Override public String toString() { return "NamespaceHandlerResolver using mappings " + getHandlerMappings(); }
7.整體流程
8.其他
注冊(cè)beanDefinition需要關(guān)注org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition,它會(huì)將beanDefinition加入beanDefinitionMap中。
到此這篇關(guān)于Spring中的之啟動(dòng)過(guò)程obtainFreshBeanFactory詳解的文章就介紹到這了,更多相關(guān)Spring的obtainFreshBeanFactory內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java開(kāi)發(fā)編程到底是用idea好還是eclipse好
這篇文章主要介紹了Java開(kāi)發(fā)編程到底是用idea好還是eclipse好,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08org.springframework.beans.BeanInstantiationException異常解決
本文主要介紹了org.springframework.beans.BeanInstantiationException異常解決,大多數(shù)情況下,這個(gè)異常是由于簡(jiǎn)單的配置錯(cuò)誤或者代碼問(wèn)題導(dǎo)致的,下面就來(lái)具體解決一下2024-03-03詳解SpringBoot如何優(yōu)雅的進(jìn)行測(cè)試打包部署
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何優(yōu)雅的進(jìn)行測(cè)試打包部署,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12java開(kāi)發(fā)中防止重復(fù)提交的幾種解決方案
我們?nèi)粘i_(kāi)發(fā)中有很多的應(yīng)用場(chǎng)景都會(huì)遇到重復(fù)提交問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于java開(kāi)發(fā)中防止重復(fù)提交的幾種解決方案,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10Spring Boot Actuator監(jiān)控端點(diǎn)小結(jié)
這篇文章主要介紹了Spring Boot Actuator監(jiān)控端點(diǎn)小結(jié),需要的朋友可以參考下2017-06-06