1. 程式人生 > >spring源碼之IOC的核心部分

spring源碼之IOC的核心部分

屬性 gis spring啟動 isinf 上下文對象 cor 說明 equals getbean

前言

上一篇對啟動時的整個流程進行了大體的分析,這一篇ioc的核心部分進行分析。包括初始化過程和依賴註入過程。

概述

在分析之前先看幾個類圖

技術分享圖片

DefaultListableBeanFactory是ioc的一個核心類,可以看到我們關心的bean定義和單例bean都註冊在它的屬性上。

技術分享圖片

ClassPathXmlApplicationContext註意一下,它實現了事件發布、資源解析、消息源、資源加載的幾個接口。

ClassPathXmlApplicationContext實現了資源加載接口,可以把xml配置的信息加載到Resource對象中。

技術分享圖片

XmlBeanDefinitionReader把Resouce中的內容讀到Document對象中

技術分享圖片

DefaultBeanDefinitionDocumentReader負責把讀取Document內容轉化成BeanDefinition對象

源碼分析之初始化過程

  • 接著上篇的源碼進行分析,直接來到在AbstractApplicationContext類的refresh方法中調用的obtainFreshBeanFactory方法。這個方法是我們初始化過程的入口。這個方法做了三件事
    • 創建一個DefaultListableBeanFactory
    • 把配置文件中的bean定義轉換成BeanDefintion對象並註冊到DefaultListableBeanFactory上
    • 返回這個DefaultListabelBeanFactory對象  
//AbstractApplicationContext類的方法
//創建並返回DefaultListableBeanFactory
protected
ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); }
return beanFactory; }
  • 刷新beanFactory,這個方法主要分為四步,我們關心的是第二步和第四步
    • 如果之前已經有創建過beanFactory,那麽這裏會對註冊在它上面的bean進行銷毀,並關閉這個beanFactory
    • 創建一個beanFactory,這個就是去創建一個DefaultListBeanFactory
    • 一些對beanFactory的自定義處理,這裏設置了bean定義是否可以重寫,是否可以循環引用
    • 最後,也是最重要的,加載bean定義  
//AbstractRefreshableApplicationContext類的方法
protected
final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); 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定義,這裏主要做了三件事。在這裏我們看到了創建了一個XmlBeanDefinitionReader對象
    • 創建XmlBeanDefinitionReader對象
    • 進行一些設置和加載前的處理
    • 加載bean定義,繼續向下委派
//AbstractXmlApplicationContext類的方法
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); }
  • 拿到Resource對象,整個過程如下
    • 如果是Resource對象,則直接加載。但由於我們這裏是路徑,先對每一個路徑進行循環
    • 拿到ResourceLoader,當前ClassPathXmlApplicationContext對象就是並且它實現了ResourcePatternResolver接口,那麽用當前的上下文對象把定義路徑上的xml文件讀取到Resource對象中
    • XmlBeanDefinitionReader掊下來再對Resource對象進行加載  
//AbstractXmlApplicationContext類的方法
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); } }
//AbstractBeanDefinitionReader類的方法
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; }
//AbstractBeanDefinitonReader類的方法
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); }
//AbstractBeanDefinitionReader類的方法
public int loadBeanDefinitions(String location, 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); 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; } }
  • 把Resource對象封裝成InputSource對象
//AbstractBeanDefinitionReader類的方法
public
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; }
//XmlBeanDefinitionReader類的方法
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); }
//XmlBeanDefintionReader類的方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } //使用ThreadLocal,實現隨用隨取 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } //判斷資源文件有沒有重復載入 if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
  • 通過DefaultDocumentLoader把InputSource對象讀取到Document對象中
//XmlBeanDefinitionReader類的方法
protected
int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } 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); } }
  • 創建BeanDefintionDocumentReader對象,這裏創建的是DefaultBeanDefiniitonDocumentReader對象
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}
  • 獲取合適的解析器。創建一個BeanDefintionParserDelegate對象,這個對象可以幫助找到合適解析器,在AOP的分析中有說到,這裏不說明。對於bean命名空間下的,會走默認的元素解析。 這裏我們可以先看到對profile標簽進行了解析
//DefaultBeanDefintionDocumentReader類的方法
public
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } //DefaultBeanDefintionDocumentReader類的方法 protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
//DefaultBeanDefintioinDocumentReader類的方法
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); } }
  • 這裏我們看到了對我們常用的import,alias,bean,beans進行了解析。現在我們著重看下對bean的解析
//DefaultBeanDefintionDocumentReader類的方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}
  • bean標簽的解析,這裏很顯然的兩步
    • 解析element得到BeanDefinitionHolder
    • 註冊BeanDefintion
//DefaultBeanDefintionDocumentReader類的方法
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));
    }
}

總結

本篇主要對spring啟動時的做了描述,比較說事件、後置處理器註冊等等。下一篇會對spring的核心-ioc進行總結

參考鏈接

https://www.cnblogs.com/niejunlei/archive/2016/11/11/6054713.html(prepareBeanFactory)

https://www.cnblogs.com/wade-luffy/p/6074088.html(生命周期後置處理器)

https://blog.csdn.net/zhangduilei/article/details/76172355(註冊JMX)

spring源碼之IOC的核心部分