作者:莫那魯道
鏈接:http://thinkinjava.cn
引言
作爲Java程序員,Spirng我們再熟悉不過,可以說比自己的女朋友還要親密,每天都會和他在一起,然而我們真的瞭解spring嗎?
我們都知道,Spring的核心是IOC和AOP,但樓主認爲,如果從這兩個核心中挑選一個更重要的,那非IOC莫屬。AOP也是依賴於IOC,從某些角度講,AOP就是IOC的一個擴展功能。
什麼是IOC? IOC解決了什麼問題?IOC的原理是什麼?Spring的IOC是怎麼實現的?今天我們將會將這幾個問題一起解決。
1. 什麼是IOC?
控制反轉(Inversion of Control,縮寫爲IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。
其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。
通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。
這是維基百科的說法,樓主按照自己的思路分析一下IOC,樓主認爲,分析一個問題,或者說證明一個事情,有2種方法,一是正向驗證,即按照該事物的邏輯去驗證正確性,還有一種是反向驗證,證明該事物是否正確。
樓主想反向證明IOC,我們提出一個疑問:如果沒有IOC會怎麼樣?
想象一下,在沒有IOC的世界裏,我們的系統會有大量的對象,這些對象有些是數據,有些是處理數據的。
並且各個對象相互依賴,我們需要控制他們的依賴關係,什麼時候new ,什麼時候銷燬,什麼時候需要單例,什麼時候不需要單例等等這些問題。
你能想象嗎?當你一個系統有幾千個類,你如何管理他們的依賴關係,說起依賴,我們可能會想起 maven 或者 gradle,他們管理着我們的 jar 包依賴,而我們的系統代碼呢?
但是如果有一種東西,他能夠幫助我們管理所有類的創建,銷燬,是否是單例模式,類與類之間的多層依賴關係(在我們的MVC框架中,3層依賴已經是最少),那該多好,我們只需要關注業務邏輯。於是 ,IOC誕生了。
2. IOC 解決了什麼問題?
簡單來說, IOC 解決了類與類之間的依賴關係。程序員將控制類與類之間依賴的權利
交給了IOC,即:控制被反轉了。
3. IOC 的原理是什麼?
其實 IOC 的原理很簡單,底層就是java的反射。給定一個字符串能創建一個實例,利用set方法對實例的依賴進行注入。
我們來一段代碼證明一下是多麼的簡單:
可以看到該代碼非常的簡單,但實際上IOC 就是這麼簡單,在真正的開發中,我們只需要在配置文件給定一個類名字符串,就什麼都不用管了,對象就會創建出來,系統啓動完畢之後,我們只需要直接使用該對象就好了,不必自己去new。
解決了我們的對象創建問題。我們通過反射調用該方法的setText方法,完成了依賴注入。我們不再需要去new,然後去set,IOC 已經爲我們做好了一切。
介紹完了幾個基本知識,其實都是爲我們今天的重頭戲做準備,Spring的IOC是怎麼實現的?
4. Spring的IOC是怎麼實現的?
這是一個浩大的問題,雖然底層實現可能就那麼幾行代碼,但樓主說過,所有框架的底層技術都很簡單,但是我們的框架大師們爲了軟件的健壯性,擴展性和性能,做了無數的優化,我們的系統源碼也就變得越來越復。
spirng的 release 版本至今已經到了 5.0.3,和最初的 interface21 已經有了翻天覆地的變化,現在也有了springboot, springcloud,儼然一個龐大的spring家族,想分析源碼的我們該從哪裏下手呢?
萬劍歸宗,始於一處。
Bean。
我們要研究spring的IOC,我們要了解的就是spring的bean,這是spring的核心的核心。雖然bena依賴着context 模塊提供bean的環境,依賴core 提供着一系列強化的工具。
但今天我們不關心,我們只關係bean。只關心IOC。就像這個信息過載,技術不斷更新的時代,程序們需要有自己的判斷,自己需要研究什麼,什麼是最重要的?扯遠了。
在開始研究源碼之前,樓主有必要介紹一下IOC的一些核心組件,否則一旦進入源碼,就會被細節捆住,無法從宏觀的角度理解IOC。
- BeanFactory:這是IOC容器的接口定義,如果將IOC容器定位爲一個水桶,那麼BeanFactory 就定義了水桶的基本功能,能裝水,有把手。這是最基本的,他的實現類可以拓展水桶的功能。
- ApplicationContext:這是我們最常見的,上面我們說水桶,BeanFactory是最基本的水桶,而 ApplicationContext 則是擴展後的水桶,它通過繼承 MessageSource,ResourceLoader,ApplicationEventPublisher 接口,在BeanFactory 簡單IOC容器的基礎上添加了許多對高級容器的支持。
- BeanDefinition:我們知道,每個bean都有自己的信息,各個屬性,類名,類型,是否單例,這些都是bena的信息,spring中如何管理bean的信息呢?對,就是 BeanDefinition, Spring通過定義 BeanDefinition 來管理基於Spring的應用中的各種對象以及他們直接的相互依賴關係。BeanDefinition 抽象了我們對 Bean的定義,是讓容器起作用的主要數據類型。對 IOC 容器來說,BeanDefinition 就是對依賴反轉模式中管理的對象依賴關係的數據抽象,也是容器實現依賴反轉功能的核心數據結構。
4.1. 搭建源碼研究環境
樓主研究源碼的思路有2個,一個是創建一個簡單的spirng maven 項目,還有一個是直接從 spirng 的github 上 clone 源碼。
這是樓主的普通 maven 項目:
這是樓主的 clone 的 spring-framework 源碼:
注意:clone 該源碼的時候,樓主很艱辛,因爲要科學上網,否則 gradle 無法下載依賴會導致報錯。如果各位無法科學上網,可以使用 maven 項目勉強學習。
4.2. 開啓研究源碼第一步
我們打開spring-framework 源碼。
還記的我們初學spring的寫的第一行代碼是什麼嗎?
怎麼寫配置文件樓主就不說了,我們回憶一下我們最初學spring的時候,雖然現在都是2017年了,我們都用springboot,都是用註解了,但spring的核心代碼還是 spring 之父 Rod Johnson 在 2001 年寫的。所以不影響我們學習spring 的核心。
我們仔細看看該代碼(該代碼位置必須在spring-context模塊下):
package test;import org.springframework.beans.tests.Person;import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;public class Test { public static void main(String[] args) throws ClassNotFoundException { ApplicationContext ctx = new FileSystemXmlApplicationContext ("spring-beans/src/test/resources/beans.xml"); System.out.println("number : " + ctx.getBeanDefinitionCount()); ((Person) ctx.getBean("person")).work(); } }
熟悉的 ApplicatContext ,看名字是應用上下文,什麼意思呢?就是spirng整個運行環境的背景,好比一場舞臺劇,ApplicatContext 就是舞臺,IOC 管理的Bean 就是演員,Core 就是道具。而ApplicatContext 的標準實現是 FileSystemXmlApplicationContext。
該類的構造方法中包含了容器的啓動,IOC的初始化。所以我們 debug 啓動該項目,運行main方法。打好斷點。
4.3. 從 FileSystemXmlApplicationContext 開始剖析
從這裏開始,我們即將進入複雜的源碼。
我們進入 FileSystemXmlApplicationContext 的構造方法:
可以看到該構造方法被重載了,可以傳遞 configLocation 數組,也就是說,可以傳遞過個配置文件的地址。默認刷新爲true,parent 容器爲null。進入另一個構造器:
該構造器做了2件事情,一是設置配置文件,二是刷新容器,我們可以感覺到,refresh 方法纔是初始化容器的重要方法。我們進入該方法看看:該方法是 FileSystemXmlApplicationContext 的父類 AbstractApplicationContext 的方法。
4.4. AbstractApplicationContext.refresh() 方法實現
/** * * 1. 構建Be按Factory,以便產生所需要的bean定義實例 * 2. 註冊可能感興趣的事件 * 3. 創建bean 實例對象 * 4. 觸發被監聽的事件 * */ @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 爲刷新準備應用上下文 prepareRefresh(); // 告訴子類刷新內部bean工廠,即在子類中啓動refreshBeanFactory()的地方----創建bean工廠,根據配置文件生成bean定義 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 在這個上下文中使用bean工廠 prepareBeanFactory(beanFactory); try { // 設置BeanFactory的後置處理器 postProcessBeanFactory(beanFactory); // 調用BeanFactory的後處理器,這些後處理器是在Bean定義中向容器註冊的 invokeBeanFactoryPostProcessors(beanFactory); // 註冊Bean的後處理器,在Bean創建過程中調用 registerBeanPostProcessors(beanFactory); //對上下文的消息源進行初始化 initMessageSource(); // 初始化上下文中的事件機制 initApplicationEventMulticaster(); // 初始化其他的特殊Bean onRefresh(); // 檢查監聽Bean並且將這些Bean向容器註冊 registerListeners(); // 實例化所有的(non-lazy-init)單件 finishBeanFactoryInitialization(beanFactory); // 發佈容器事件,結束refresh過程 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 爲防止bean資源佔用,在異常處理中,銷燬已經在前面過程中生成的單件bean destroyBeans(); // 重置“active”標誌 cancelRefresh(ex); throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
可以說該方法就是整個IOC容器初始化的所有邏輯。因此,如果讀懂了該方法的每一行代碼,就瞭解了spring的整個功能。該方法的調用層次之深可以想象一下。
我們先大致說下該方法的步驟:
- 構建BeanFactory,以便於產生所需的 Bean。
- 註冊可能感興趣的事件。
- 常見Bean實例對象。
- 觸發被監聽的事件。
我們一個個來看: 首先構建BeanFactory,在哪裏實現的呢?也就是obtainFreshBeanFactory 方法,返回了一個ConfigurableListableBeanFactory,該方法調用了 refreshBeanFactory() ,該方法是個模板方法,交給了 AbstractRefreshableApplicationContext 去實現。我們看看該方法實現:
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { // 如果存在就銷燬 destroyBeans(); closeBeanFactory(); } try { // new DefaultListableBeanFactory(getInternalParentBeanFactory()) DefaultListableBeanFactory beanFactory = createBeanFactory(); // 設置序列化 beanFactory.setSerializationId(getId()); // 定製的BeanFactory customizeBeanFactory(beanFactory); // 使用BeanFactory加載bean定義 AbstractXmlApplicationContext loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
可以看到BeanFactory的創建過程,首先判斷是否存在了 BeanFactory,如果有則銷燬重新創建,調用 createBeanFactory 方法,該方法中就是像註釋寫的:創建了 DefaultListableBeanFactory ,也既是說,DefaultListableBeanFactory 就是 BeanFactory的默認實現。然後我們看到一個很感興趣的方法。
就是 loadBeanDefinitions(beanFactory),看名字是加載 Definitions,這個我們很感興趣,我們之前說過, Definition 是核心之一,代表着 IOC 中的基本數據結構。該方法也是個抽象方法,默認實現是 AbstractXmlApplicationContext ,我們看看該方法實現:
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. 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); }
該方法我沒有寫中文註釋,我們看看英文註釋: 首先創建一個 XmlBeanDefinitionReader ,用於讀取XML中配置,設置了環境,資源加載器,最後初始化,加載。可以說,該方法將加載,解析Bean的定義,也就是把用戶定義的數據結構轉化爲 IOC容器中的特定數據結構。而我們關心的則是最後一行的 loadBeanDefinitions(beanDefinitionReader) 方法。
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); } }
該方法會略過第一個if塊,進入第二個if塊,進入 AbstractBeanDefinitionReader.loadBeanDefinitions(String… locations) 方法,該方法內部循環加載配置文件:
@Override public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { counter += loadBeanDefinitions(location); } return counter; }
我們關心的是 for 循環中的loadBeanDefinitions(location)方法,該方法核心邏輯在 AbstractBeanDefinitionReader.loadBeanDefinitions(String location, @Nullable SetactualResources) 方法中:
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources);// 根據配置文件加載bean定義 if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
該方法首先獲取資源加載器,然後進入 if 塊,獲取資源數組,調用 loadBeanDefinitions(resources) ,根據配置文件加載Bean定義。
進入該方法後,循環加載resource 資源數組,進入 loadBeanDefinitions(resource) 方法中,最後進入到 XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) 方法中,該方法主要調用 doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 方法。我們有必要看看該方法實現:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource);// 真正的註冊bean } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } }
可以看出該方法主要邏輯是根據輸入流加載 Document 文檔對象,然後根據得到的文檔對象註冊到容器,因此我們看看倒是是如何註冊到容器的。
該方法首先創建一個 BeanDefinitionDocumentReader, 用於讀取 BeanDefinition,該對象會調用 registerBeanDefinitions(doc, createReaderContext(resource)) 方法。
該方法最後從文檔對象獲取根元素,最後調用 DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(root) 進行註冊。
該方法最核心的邏輯就是調用 parseBeanDefinitions(root, this.delegate),我們看看該方法具體實現:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate);// 解析 } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
該方法就是一個解析XML 文檔的步驟,核心是調用 parseDefaultElement(ele, delegate),我們進入該方法查看,該方法調用了 processBeanDefinition(ele, delegate) 方法進行解析。我們有必要看看該方法:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// 解析 if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());// 開始註冊 } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
首先創建一個 BeanDefinitionHolder,該方法會調用 BeanDefinitionReaderUtils.registerBeanDefinition 方法, 最後執行容器通知事件。該靜態方法實現如下:
*/ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 註冊 // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
可以看到首先從bean的持有者那裏獲取了beanName,然後調用 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()), 將bena的名字和 BeanDefinition 註冊,我們看看最後的邏輯:
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase // 最終放進這個map 實現註冊 this.beanDefinitionMap.put(beanName, beanDefinition);// 走這裏 // private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
該方法可以說是註冊bean的最後一步,將beanName和 beanDefinition 放進一個 ConcurrentHashMap(256) 中。
那麼這個 beanDefinition 是時候創建的呢? 就是在 DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法中,在這裏創建了 BeanDefinitionHolder, 而該實例中解析Bean並將Bean 保存在該對象中。
所以稱爲持有者。該實例會調用 parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) 方法,該方法用於解析XML文件並創建一個 BeanDefinitionHolder 返回,該方法會調用 parseBeanDefinitionElement(ele, beanName, containingBean) 方法, 我們看看該方法:
@Nullable public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim();// 類全限定名稱 } String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { AbstractBeanDefinition bd = createBeanDefinition(className, parent);// 創建 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
我們看看該方法,可以看到,該方法從XML元素中取出 class 元素,然後拿着className調用 createBeanDefinition(className, parent) 方法,該方法核心是調用 BeanDefinitionReaderUtils.createBeanDefinition 方法,我們看看該方法:
public static AbstractBeanDefinition createBeanDefinition( @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition();// 泛型的bean定義,也就是最終生成的bean定義。 bd.setParentName(parentName); if (className != null) { if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader));// 設置Class 對象 } else { bd.setBeanClassName(className); } } return bd; }
該方法很簡單,創建一個 Definition 的持有者,然後設置該持有者的Class對象,該對象就是我們在配置文件中配置的Class對象。最後返回。
到這裏,我們一走完了第一步,創建bean工廠,生成Bean定義。但還沒有實例化該類。
由於文章不能超過5萬字,所以後面的放在下一章節講解。