目錄html
1、ApplicationContext接口設計node
2、深刻源碼,看IOC容器初始化web
===========正文分割線===========spring
前面一篇概覽了IOC容器的接口設計。設計模式
本文從ApplicationContext接口的一個實現類ClassPathXmlApplicationContext入手,分析容器初始化過程。先看一下ApplicationContext接口設計:緩存
ApplicationContext是spring中較高級的容器。和BeanFactory相似,它能夠加載配置文件中定義的bean,當有請求的時候分配bean。 另外,它增長了企業所須要的功能,好比,從屬性文件解析文本信息和將事件傳遞給所指定的監聽器。接口設計圖以下:數據結構
,ide
ApplicationContext繼承5個接口:函數
1.2個核心接口:post
ListableBeanFactory:支持獲取bean 工廠的全部bean實例
HierarchicalBeanFactory:支持繼承關係
2.3個拓展接口:
MessageSource:提供國際化支持
ApplicationEventPublisher:支持事件驅動模型中的事件發佈器,這些事件和Bean的生命週期的結合爲Bean的管理提供了便利。
ResourcePatternResolver:資源解析器
常見實現類:
1.FileSystemXmlApplicationContext:從指定文件地址的加載xml定義的bean
2.ClassPathXmlApplicationContext:從類路徑下載入xml定義的bean
3.XmlWebApplicationContext:web 應用程序的範圍內載入xml定義的bean
爲了方便理解和追蹤代碼,使用經常使用實現類ClassPathXmlApplicationContext寫了一個小例子,步驟以下:
1).在類路徑下新建xml,定義一個bean,其中daoImpl就是bean的名字,spring.aop.xml.dao.impl.DaoImpl對應具體的一個pojo.
1 <bean id="daoImpl" class="spring.aop.xml.dao.impl.DaoImpl" />
2).main方法中直接載入xml,而後獲取bean,最後執行bean實例的方法。
1 public static void main(String[] args) { 2 //源碼入口,從類路徑下讀取xml 3 ApplicationContext ac1 = new ClassPathXmlApplicationContext("aop.xml"); 4 Dao dao = (Dao)ac1.getBean("daoImpl");//根據名稱獲取Bean 5 dao.select();//執行Bean實例方法
}
下面咱們就分析ClassPathXmlApplicationContext源碼,來看看都作了什麼。
DefaultResourceLoader,該類設置classLoader,而且將配置文件 封裝爲Resource文件。
AbstractApplicationContext,該類完成了大部分的IOC容器初始化工做,同時也提供了擴展接口留給子類去重載。該類的refresh()函數是核心初始化操做。
AbstractRefreshableApplicationContext,該類支持刷新BeanFactory。
AbstractRefreshableConfigApplicationContext,該類保存了配置文件路徑
AbstractXmlApplicationContext:該類支持解析bean定義文件
最後ClassPathXmlApplicationContext:只提供了一個簡單的構造函數
Spring 將類職責分開,造成職責鏈,每一層次的擴展 都只是添加了某個功能
而後父類定義大量的模板,讓子類實現,父類層層傳遞到子類 直到某個子類重載了抽象方法。這裏應用到了職責鏈設計模式和模板設計模式,IOC是個容器工廠設計模式。
1 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) 2 throws BeansException { 3 4 super(parent);//把ApplicationContext做爲父容器,上述測試類中因爲直接載入的xml,沒有父容器因此實際傳了null
5 setConfigLocations(configLocations);//替換${}後設置配置路徑 6 if (refresh) { 7 refresh();//核心方法 8 } 9 }
ClassPathXmlApplicationContext的refresh()實際上就是調用了AbstractApplicationContext的refresh()方法。全方法被synchronized同步塊鎖住,源碼以下:
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized (this.startupShutdownMonitor) { 3 //準備刷新的上下文環境,例如對系統屬性或者環境變量進行準備及驗證。 4 prepareRefresh(); 5 6 //啓動子類的refreshBeanFactory方法.解析xml 7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 8 9 //爲BeanFactory配置容器特性,例如類加載器、事件處理器等. 10 prepareBeanFactory(beanFactory); 11 12 try { 13 //設置BeanFactory的後置處理. 空方法,留給子類拓展用。 14 postProcessBeanFactory(beanFactory); 15 16 //調用BeanFactory的後處理器, 這些後處理器是在Bean定義中向容器註冊的. 17 invokeBeanFactoryPostProcessors(beanFactory); 18 19 //註冊Bean的後處理器, 在Bean建立過程當中調用. 20 registerBeanPostProcessors(beanFactory); 21 22 //初始化上下文中的消息源,即不一樣語言的消息體進行國際化處理 23 initMessageSource(); 24 25 //初始化ApplicationEventMulticaster bean,應用事件廣播器 26 initApplicationEventMulticaster(); 27 28 //初始化其它特殊的Bean, 空方法,留給子類拓展用。 29 onRefresh(); 30 31 //檢查並向容器註冊監聽器Bean 32 registerListeners(); 33 34 //實例化全部剩餘的(non-lazy-init) 單例Bean. 35 finishBeanFactoryInitialization(beanFactory); 36 37 //發佈容器事件, 結束refresh過程. 38 finishRefresh(); 39 } 40 41 catch (BeansException ex) { 42 if (logger.isWarnEnabled()) { 43 logger.warn("Exception encountered during context initialization - " + 44 "cancelling refresh attempt: " + ex); 45 } 46 47 //銷燬已經建立的單例Bean, 以免資源佔用. 48 destroyBeans(); 49 50 //取消refresh操做, 重置active標誌. 51 cancelRefresh(ex); 52 53 // Propagate exception to caller. 54 throw ex; 55 } 56 57 finally { 58 //重置Spring的核心緩存 60 resetCommonCaches(); 61 } 62 } 63 }
refresh方法中obtainFreshBeanFactory方法調用了refreshBeanFactory,該方法使用DefaultListableBeanFactory去定位resources資源
1 protected final void refreshBeanFactory() throws BeansException { 2 if (hasBeanFactory()) { 3 destroyBeans(); 4 closeBeanFactory(); 5 } 6 try {//建立並設置DefaultListableBeanFactory同時調用loadBeanDefinitions載入loadBeanDefinition 7 DefaultListableBeanFactory beanFactory = createBeanFactory(); 8 beanFactory.setSerializationId(getId()); 9 customizeBeanFactory(beanFactory); 10 loadBeanDefinitions(beanFactory);//核心方法 11 synchronized (this.beanFactoryMonitor) { 12 this.beanFactory = beanFactory; 13 } 14 } 15 catch (IOException ex) { 16 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); 17 } 18 }
loadBeanDefinitions其具體實如今AbstractXmlApplicationContext中,定義了一個Reader做爲入參執行載入過程:
1 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { 2 // 爲給定的bean工廠建立一個reader 3 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 4 5 // Configure the bean definition reader with this context's 6 // resource loading environment. 7 beanDefinitionReader.setEnvironment(this.getEnvironment()); 8 beanDefinitionReader.setResourceLoader(this); 9 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); 10 11 // Allow a subclass to provide custom initialization of the reader, 12 // then proceed with actually loading the bean definitions. 13 initBeanDefinitionReader(beanDefinitionReader); 14 loadBeanDefinitions(beanDefinitionReader);//核心方法 15 }
loadBeanDefinitions方法以下:
1 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { 2 Resource[] configResources = getConfigResources(); 3 if (configResources != null) { 4 reader.loadBeanDefinitions(configResources); 5 } 6 String[] configLocations = getConfigLocations(); 7 if (configLocations != null) { 8 reader.loadBeanDefinitions(configLocations); 9 } 10 }
getConfigResources採用模板方法設計模式,具體的實現由子類完成,實際上這裏getConfigResources調用的就是子類ClassPathXmlApplicationContext的getConfigResources方法。ClassPathXmlApplicationContext繼承了DefaultResourceLoader,具有了Resource加載資源的功能。至此完成了Resource定位!
這裏支持2種模式:1.模板匹配多資源,生成Resource[]。2.載入單個資源url絕對地址,生成一個Resource
1 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { 2 ResourceLoader resourceLoader = getResourceLoader();//獲取ResourceLoader資源加載器 3 if (resourceLoader == null) { 4 throw new BeanDefinitionStoreException( 5 "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); 6 } 7 // 1.匹配模板解析 ClassPathXmlApplicationContext是ResourcePatternResolver接口的實例 8 if (resourceLoader instanceof ResourcePatternResolver) { 9 10 try {//接口ResourcePatternResolver 11 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); 12 int loadCount = loadBeanDefinitions(resources); 13 if (actualResources != null) { 14 for (Resource resource : resources) { 15 actualResources.add(resource); 16 } 17 } 18 if (logger.isDebugEnabled()) { 19 logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); 20 } 21 return loadCount; 22 } 23 catch (IOException ex) { 24 throw new BeanDefinitionStoreException( 25 "Could not resolve bean definition resource pattern [" + location + "]", ex); 26 } 27 } 28 else { 29 // 2.載入單個資源url絕對地址 30 Resource resource = resourceLoader.getResource(location); 31 int loadCount = loadBeanDefinitions(resource); 32 if (actualResources != null) { 33 actualResources.add(resource); 34 } 35 if (logger.isDebugEnabled()) { 36 logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); 37 } 38 return loadCount; 39 } 40 }
loadBeanDefinitions最終調用XmlBeanDefinitionReader.doLoadBeanDefinitions(),以下:
1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) 2 throws BeanDefinitionStoreException { 3 try {// 取得xml文件的Document,解析過程是由DocumentLoader完成,默認爲DefaultDocumentLoader 4 Document doc = doLoadDocument(inputSource, resource); 5 return registerBeanDefinitions(doc, resource);// 啓動對BeanDefinition的詳細解析過程,這個解析會使用到spring的BEAN配置規則 6 } 7 catch (BeanDefinitionStoreException ex) { 8 throw ex; 9 } 10 catch (SAXParseException ex) { 11 throw new XmlBeanDefinitionStoreException(resource.getDescription(), 12 "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); 13 } 14 catch (SAXException ex) { 15 throw new XmlBeanDefinitionStoreException(resource.getDescription(), 16 "XML document from " + resource + " is invalid", ex); 17 } 18 catch (ParserConfigurationException ex) { 19 throw new BeanDefinitionStoreException(resource.getDescription(), 20 "Parser configuration exception parsing XML from " + resource, ex); 21 } 22 catch (IOException ex) { 23 throw new BeanDefinitionStoreException(resource.getDescription(), 24 "IOException parsing XML document from " + resource, ex); 25 } 26 catch (Throwable ex) { 27 throw new BeanDefinitionStoreException(resource.getDescription(), 28 "Unexpected exception parsing XML document from " + resource, ex); 29 } 30 }
registerBeanDefinitions是按照spring的bean配置規則解析,源碼以下:
1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { 2 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); 3 int countBefore = getRegistry().getBeanDefinitionCount(); 4 documentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 核心方法 5 return getRegistry().getBeanDefinitionCount() - countBefore; 6 }
至此就完成了BeanDefinition的載入,BeanDefinition的載入分爲兩個部分,
1.調用xml解析器獲得的document對象,可是這個對象並無按照spring的bean規則進行解析。
2.DefaultBeanDefinitionDocumentReader的registerBeanDefinitions按照Spring的Bean規則進行解析。
registerBeanDefinitions方法調用了doRegisterBeanDefinitions
1 protected void doRegisterBeanDefinitions(Element root) { 2 // Any nested <beans> elements will cause recursion in this method. In 3 // order to propagate and preserve <beans> default-* attributes correctly, 4 // keep track of the current (parent) delegate, which may be null. Create 5 // the new (child) delegate with a reference to the parent for fallback purposes, 6 // then ultimately reset this.delegate back to its original (parent) reference. 7 // this behavior emulates a stack of delegates without actually necessitating one. 8 BeanDefinitionParserDelegate parent = this.delegate; 9 this.delegate = createDelegate(getReaderContext(), root, parent); 10 11 if (this.delegate.isDefaultNamespace(root)) { 12 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); 13 if (StringUtils.hasText(profileSpec)) { 14 String[] specifiedProfiles = StringUtils.tokenizeToStringArray( 15 profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); 16 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { 17 if (logger.isInfoEnabled()) { 18 logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + 19 "] not matching: " + getReaderContext().getResource()); 20 } 21 return; 22 } 23 } 24 } 25 26 preProcessXml(root); 27 parseBeanDefinitions(root, this.delegate);// 從Document的根元素開始進行Bean定義的Document對象 28 postProcessXml(root); 29 30 this.delegate = parent; 31 }
1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { 2 if (delegate.isDefaultNamespace(root)) { 3 NodeList nl = root.getChildNodes(); 4 for (int i = 0; i < nl.getLength(); i++) { 5 Node node = nl.item(i); 6 if (node instanceof Element) { 7 Element ele = (Element) node; 8 if (delegate.isDefaultNamespace(ele)) { 9 parseDefaultElement(ele, delegate); 10 } 11 else { 12 delegate.parseCustomElement(ele); 13 } 14 } 15 } 16 } 17 else { 18 delegate.parseCustomElement(root); 19 } 20 } 21 22 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { 23 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { 24 importBeanDefinitionResource(ele); 25 } 26 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { 27 processAliasRegistration(ele); 28 } 29 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { 30 processBeanDefinition(ele, delegate); 31 } 32 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { 33 // recurse 34 doRegisterBeanDefinitions(ele); 35 } 36 }
processBeanDefinition就是對bean標籤的解析和註冊
1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 2 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// 1.解析 3 if (bdHolder != null) { 4 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//代理去裝飾:典型的裝飾器模式 5 try { 6 // 2.向IOC容器註冊Bean定義+bean工廠 7 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 8 } 9 catch (BeanDefinitionStoreException ex) { 10 getReaderContext().error("Failed to register bean definition with name '" + 11 bdHolder.getBeanName() + "'", ele, ex); 12 } 13 // 3.觸發註冊事件: spring只提供了EmptyReaderEventListener空實現,若是須要你能夠自定義 14 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 15 } 16 }
解析:parseBeanDefinitionElement方法就是具體的解析入口。解析elemnent->BeanDefinitionHolder,追蹤parseBeanDefinitionElement:
1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { 2 String id = ele.getAttribute(ID_ATTRIBUTE);// 獲取id 3 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);// 獲取name 4 5 List<String> aliases = new ArrayList<String>();// 獲取別名 6 if (StringUtils.hasLength(nameAttr)) { 7 String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); 8 aliases.addAll(Arrays.asList(nameArr)); 9 } 10 11 String beanName = id; 12 if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { 13 beanName = aliases.remove(0); 14 if (logger.isDebugEnabled()) { 15 logger.debug("No XML 'id' specified - using '" + beanName + 16 "' as bean name and " + aliases + " as aliases"); 17 } 18 } 19 20 if (containingBean == null) { 21 checkNameUniqueness(beanName, aliases, ele); 22 } 23 24 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); 25 if (beanDefinition != null) { 26 if (!StringUtils.hasText(beanName)) { 27 try { 28 if (containingBean != null) { 29 beanName = BeanDefinitionReaderUtils.generateBeanName( 30 beanDefinition, this.readerContext.getRegistry(), true); 31 } 32 else { 33 beanName = this.readerContext.generateBeanName(beanDefinition); 34 // Register an alias for the plain bean class name, if still possible, 35 // if the generator returned the class name plus a suffix. 36 // This is expected for Spring 1.2/2.0 backwards compatibility. 37 String beanClassName = beanDefinition.getBeanClassName(); 38 if (beanClassName != null && 39 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && 40 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { 41 aliases.add(beanClassName); 42 } 43 } 44 if (logger.isDebugEnabled()) { 45 logger.debug("Neither XML 'id' nor 'name' specified - " + 46 "using generated bean name [" + beanName + "]"); 47 } 48 } 49 catch (Exception ex) { 50 error(ex.getMessage(), ele); 51 return null; 52 } 53 } 54 String[] aliasesArray = StringUtils.toStringArray(aliases); 55 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); 56 } 57 58 return null; 59 }
好吧,parseBeanDefinitionElement纔是核心方法,追蹤:
1 public AbstractBeanDefinition parseBeanDefinitionElement( 2 Element ele, String beanName, BeanDefinition containingBean) { 3 4 this.parseState.push(new BeanEntry(beanName)); 5 6 String className = null; 7 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { 8 className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); 9 } 10 11 try { 12 String parent = null; 13 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { 14 parent = ele.getAttribute(PARENT_ATTRIBUTE); 15 }// 這裏生成須要的BeanDefinition對象,爲Bean定義信息的載入作準備 16 AbstractBeanDefinition bd = createBeanDefinition(className, parent); 17 // 1.解析<bean>元素屬性 18 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); 19 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//2.解析description 20 //對各類BEAN元素信息進行解析 21 parseMetaElements(ele, bd);// 3.解析<meta>子元素 22 parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//4.解析<lookup-method>子元素 23 parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//5.解析<replaced-method>子元素 24 25 parseConstructorArgElements(ele, bd);//6.解析<constructor-arg> 26 parsePropertyElements(ele, bd);//7.解析<property> 27 parseQualifierElements(ele, bd);//8.解析<qualifier> 28 29 bd.setResource(this.readerContext.getResource()); 30 bd.setSource(extractSource(ele)); 31 32 return bd; 33 } 34 catch (ClassNotFoundException ex) { 35 error("Bean class [" + className + "] not found", ele, ex); 36 } 37 catch (NoClassDefFoundError err) { 38 error("Class that bean class [" + className + "] depends on not found", ele, err); 39 } 40 catch (Throwable ex) { 41 error("Unexpected failure during bean definition parsing", ele, ex); 42 } 43 finally { 44 this.parseState.pop(); 45 } 46 47 return null; 48 }
通過這樣逐層的分析,咱們在xml文件中定義的BeanDefinition就被整個載入到IOC容器中,並在容器中創建了數據映射。這些數據結構能夠以AbstractBeanDefinition爲入口讓IOC容器執行索引,查詢和操做。
註冊:registerBeanDefinition方法就是具體的註冊入口。追蹤registerBeanDefinition:
1 public static void registerBeanDefinition( 2 BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 3 throws BeanDefinitionStoreException { 4 5 // Register bean definition under primary name. 6 String beanName = definitionHolder.getBeanName(); 7 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//向IoC容器註冊BeanDefinition 8 9 // 若是解析的BeanDefinition有別名, 向容器爲其註冊別名. 10 String[] aliases = definitionHolder.getAliases(); 11 if (aliases != null) { 12 for (String alias : aliases) { 13 registry.registerAlias(beanName, alias); 14 } 15 } 16 }
registerBeanDefinition具體實現類:DefaultListableBeanFactory.registerBeanDefinition方法
1 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 2 throws BeanDefinitionStoreException { 3 4 Assert.hasText(beanName, "Bean name must not be empty"); 5 Assert.notNull(beanDefinition, "BeanDefinition must not be null"); 6 7 if (beanDefinition instanceof AbstractBeanDefinition) { 8 try { 9 ((AbstractBeanDefinition) beanDefinition).validate(); 10 } 11 catch (BeanDefinitionValidationException ex) { 12 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, 13 "Validation of bean definition failed", ex); 14 } 15 } 16 17 BeanDefinition oldBeanDefinition; 18 19 oldBeanDefinition = this.beanDefinitionMap.get(beanName); 20 if (oldBeanDefinition != null) { 21 if (!isAllowBeanDefinitionOverriding()) { 22 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, 23 "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + 24 "': There is already [" + oldBeanDefinition + "] bound."); 25 } 26 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { 27 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE 28 if (this.logger.isWarnEnabled()) { 29 this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + 30 "' with a framework-generated bean definition: replacing [" + 31 oldBeanDefinition + "] with [" + beanDefinition + "]"); 32 } 33 } 34 else if (!beanDefinition.equals(oldBeanDefinition)) { 35 if (this.logger.isInfoEnabled()) { 36 this.logger.info("Overriding bean definition for bean '" + beanName + 37 "' with a different definition: replacing [" + oldBeanDefinition + 38 "] with [" + beanDefinition + "]"); 39 } 40 } 41 else { 42 if (this.logger.isDebugEnabled()) { 43 this.logger.debug("Overriding bean definition for bean '" + beanName + 44 "' with an equivalent definition: replacing [" + oldBeanDefinition + 45 "] with [" + beanDefinition + "]"); 46 } 47 } 48 this.beanDefinitionMap.put(beanName, beanDefinition); 49 } 50 else { 51 if (hasBeanCreationStarted()) { 52 // Cannot modify startup-time collection elements anymore (for stable iteration) 53 synchronized (this.beanDefinitionMap) { 54 this.beanDefinitionMap.put(beanName, beanDefinition); 55 List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); 56 updatedDefinitions.addAll(this.beanDefinitionNames); 57 updatedDefinitions.add(beanName); 58 this.beanDefinitionNames = updatedDefinitions; 59 if (this.manualSingletonNames.contains(beanName)) { 60 Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); 61 updatedSingletons.remove(beanName); 62 this.manualSingletonNames = updatedSingletons; 63 } 64 } 65 } 66 else { 67 // Still in startup registration phase 68 this.beanDefinitionMap.put(beanName, beanDefinition); 69 this.beanDefinitionNames.add(beanName); 70 this.manualSingletonNames.remove(beanName); 71 } 72 this.frozenBeanDefinitionNames = null; 73 } 74 75 if (oldBeanDefinition != null || containsSingleton(beanName)) { 76 resetBeanDefinition(beanName); 77 } 78 }
完成了BeanDefinition的註冊,就完成了IOC容器的初始化過程。容器的做用就是對這些信息進行處理和維護,這些信息就是容器創建依賴反轉的基礎。
本文先介紹ApplicationContext接口設計,再從其一個最多見實現類ClassPathXmlApplicationContext寫了一個小例子,做爲源碼追蹤的入口。
追蹤了主要包括Resourse定位、BeanDefinition的載入、解析和註冊3個模塊。至此,容器初始化(Bean已生成)已完成,下一章咱們看依賴注入的源碼。