IOC容器案例:XmlBeanFactorynode
XmlBeanFactory容器初始化過程:數據結構
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("com/zhiwei/ioc/applicationContext.xml"));
步驟1:XmlBeanFactory 使用 ClassPathResource 映射Spring XML配置文件app
new ClassPathResource("com/zhiwei/ioc/applicationContext.xml")
步驟2:初始化空白的IOC容器,而後使用XmlBeanDefinitionReader解析Spring XML配置文件,並注入到IOC容器ide
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { //傳遞父BeanFactory初始化父類 super(parentBeanFactory); //BeanDefinition解析 this.reader.loadBeanDefinitions(resource); }
步驟3: 查看XmlBeanDefinitionReader.loadBeanDefinitions() 方法post
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { 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(); } } }
方法解讀: resourcesCurrentlyBeingLoaded:經過ThreadLocal綁定EncodedResource,XmlBeanDefinitionReader就持有配置資源映射,方便後續DOM XML解析,將配置資源封裝爲 inputSource對象,而後傳遞給doLoadBeanDefinitions方法ui
步驟4:查看XmlBeanDefinitionReader.doLoadBeanDefinitions方法 源碼:this
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); }
解析: doLoadDocument方法底層經過DOM解析的方法解析Spring XML配置文件,並返回Document對象,接着調用registerBeanDefinitions進行Bean實際註冊工做spa
步驟5:查看XmlBeanDefinitionReader.registerBeanDefinitions方法實現debug
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; }
解析: getRegistry():可用於獲取IOC容器,緣由XmlBeanFactory實例化: private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); 將XML的Bean定義閱讀器與IOC容器綁定在一塊兒 registerBeanDefinitions內部調用registerBeanDefinitions註冊Bean,注意createReaderContext方法會建立XmlReaderContext,該對象會與XmlBeanDefinitionReader 綁定,從而實現與IOC容器的間接綁定,這一點對於後續的Bean實際IOC容器註冊很是重要code
步驟6:查看BeanDefinitionDocumentReader.registerBeanDefinitions方法
注意:BeanDefinitionDocumentReader主要做用就是將Spring XMl配置文件元素映射爲IOC容器中的BeanDefinition數據結構,實現真正意義上的解析、註冊Bean的功能
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
解析:將readerContext做爲BeanDefinitionDocumentReader的內置組件,而後獲取XML文件的Root節點,接着調用doRegisterBeanDefinitions方法處理
步驟7: BeanDefinitionDocumentReader.doRegisterBeanDefinitions方法代碼
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; }
解析:實際解析XMl文件的時BeanDefinitionParserDelegate對象,查看createDelegate方法:
protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); delegate.initDefaults(root, parentDelegate); return delegate; }
該方法執行時不單單返回BeanDefinitionParserDelegate 對象,還會在建立後進行Beans標籤的屬性信息的初始化工做,該方法核心代碼:
preProcessXml(root); //自定義標籤前置處理 parseBeanDefinitions(root, this.delegate); //Spring原始標籤處理 postProcessXml(root); //自定義標籤後置處理
步驟8:查看BeanDefinitionDocumentReader.parseBeanDefinitions方法代碼
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文件映射的DOM樹的節點,delegate.isDefaultNamespace(root)主要用於XML文件命名空間校驗,delegate.isDefaultNamespace(ele)用於區別配置文件中的元素是否時Spring自帶的,如果Spring自身元素則parseDefaultElement方法處理,不然parseCustomElement處理(例如自定義標籤)
步驟9:查看BeanDefinitionDocumentReader.parseDefaultElement方法代碼
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標籤的處理方法processBeanDefinition(ele, delegate);
步驟10:查看BeanDefinitionDocumentReader.processBeanDefinition方法代碼:
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 bdHolder = delegate.parseBeanDefinitionElement(ele);
主要時根據Root元素節點遍歷,而後將數據封裝到 BeanDefinitionHolder 這個數據結構,真正IOC容器的Bean註冊在 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 方法
步驟11:查看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註冊分爲Bean註冊和Bean別名註冊,主要看registry.registerBeanDefinition方法
步驟12:查看BeanDefinitionRegistry.registerBeanDefinition(這裏使用DefaultListableBeanFactory基礎IOC容器)
@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<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
解析: 首先校驗生成的BeanDefinition類型,接着校驗新建立的Bean是否在IOC容器中註冊過,若是註冊過則按照Bean的相應配置策略進行處理,例如重寫,接着根據hasBeanCreationStarted方法判斷IOC容器是否啓動過,若是未啓動則beanDefinitionMap Map記錄BeanName與BeanDefinition對象的關係,beanDefinitionNames記錄註冊的Bean名稱,這裏Map的key爲BeanName這就時IOC容器中BeanName惟一的緣由,若是IOC容器實現啓動則beanDefinitionMap直接存放,manualSingletonNames須要已有的BeanName進行校驗,最終等於beanDefinitionNames數據,至此整個XMl解析與IOC容器的初始化工做所有完成。