spring源碼之IOC的核心部分
阿新 • • 發佈:2018-08-19
屬性 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的核心部分