如下源碼基於Spring 5.0.2版本解析。node
容器,顧名思義能夠用來容納一切事物。咱們日常所說的Spring IOC容器就是一個能夠容納對象的東西。IOC全名Inversion of Control,即控制反轉,什麼是控制反轉?平時咱們代碼裏須要建立一個對象是須要經過new操做或者反射等方式建立,也就是說如今是咱們人爲地建立對象,控制對象,那麼控制反轉的意思就顯而易見了,就是將原來屬於咱們的控制權交由Spring框架進行管理,由Spring替咱們建立對象,管理對象以及對象之間的依賴關係。當咱們須要使用對象的時候直接問Spring取就能夠了。spring
對於Spring IOC的實現,總結來講就是定位、加載和註冊。定位就是Spring須要定位配置文件的位置,加載就是將配置文件加載進內存,註冊就是經過解析配置文件註冊BeanDefinition。
下面咱們從其中的一種使用Spring的方式一步一步的分析IOC的實現源碼。咱們平時編程式地使用Spring框架以下代碼所示。編程
public class TestSpring { public static void main(String[] args) { //傳入配置文件路徑信息,初始化Spring IOC容器 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml"); //從容器中獲取名稱爲world的bean實例 context.getBean("world"); } }
因此咱們分析Spring IOC實現的入口也就是ClassPathXmlApplicationContext的構造方法。ClassPathXmlApplicationContext的構造方法源碼以下:設計模式
//這裏是咱們上述初始化IOC容器的地方 public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[]{configLocation}, true, (ApplicationContext)null); } //實際調用的是這個核心方法初始化IOC容器的 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { //設置父容器信息 super(parent); //設置配置文件路徑,方便接下來的查找 this.setConfigLocations(configLocations); //判斷是否須要從新刷新IOC容器 if (refresh) { //調用父類AbstractApplicationContext的refresh方法 this.refresh(); } }
因此這裏咱們須要進入refresh方法分析Spring IOC是如何刷新的,源碼以下:緩存
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; //這裏須要進行同步操做,防止多個線程同時刷新容器 synchronized(this.startupShutdownMonitor) { //刷新前的準備工做,獲取容器的當時時間,同時給容器設置同步標識。 this.prepareRefresh(); //這裏是IOC容器初始化的核心方法,告訴子類啓動refreshBeanFactory()方法,Bean定義資源文件的載入從子類的refreshBeanFactory()方法啓動 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); //對容器進行一些相關設置,爲BeanFactory配置容器特性,例如類加載器、事件處理器等 this.prepareBeanFactory(beanFactory); try { //爲容器的某些子類指定特殊的BeanPost事件處理器 this.postProcessBeanFactory(beanFactory); //調用bean的後置處理器 this.invokeBeanFactoryPostProcessors(beanFactory); //爲BeanFactory註冊BeanPost事件處理器.BeanPostProcessor是Bean後置處理器,用於監聽容器觸發的事件 this.registerBeanPostProcessors(beanFactory); //初始化信息源,和國際化相關. this.initMessageSource(); //初始化容器事件傳播器. this.initApplicationEventMulticaster(); //調用子類的某些特殊Bean初始化方法 this.onRefresh(); //爲事件傳播器註冊事件監聽器. this.registerListeners(); //初始化全部剩餘的單例Bean this.finishBeanFactoryInitialization(beanFactory); //初始化容器的生命週期事件處理器,併發布容器的生命週期事件 this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } //銷燬已建立的Bean this.destroyBeans(); //取消refresh操做,重置容器的同步標識. this.cancelRefresh(var9); throw var9; } finally { //緩存清理工做 this.resetCommonCaches(); } } }
這裏咱們主要分析AbstractApplicationContext的obtainFreshBeanFactory方法,源碼以下:數據結構
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //這裏使用了委派設計模式,父類定義了抽象的refreshBeanFactory()方法,具體實現調用子類容器的refreshBeanFactory()方法 refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
分析AbstractApplicationContext子類AbstractRefreshableApplicationContext的refreshBeanFactory方法,源碼以下:併發
protected final void refreshBeanFactory() throws BeansException { //若是已經有容器,銷燬容器中的bean,關閉容器 if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //建立IOC容器,這裏是直接實例化DefaultListableBeanFactory對象 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //對IOC容器進行定製化,如設置啓動參數,開啓註解的自動裝配等 customizeBeanFactory(beanFactory); //調用載入Bean定義的方法,主要這裏又使用了一個委派模式,在當前類中只定義了抽象的loadBeanDefinitions方法,具體的實現調用子類容器 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
這裏主要分析Spring是如何載入Bean定義的,進入AbstractXmlApplicationContext的loadBeanDefinitions方法,源碼以下:app
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. //建立XmlBeanDefinitionReader,即建立Bean讀取器,並經過回調設置到容器中去,容器使用該讀取器讀取Bean定義資源 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. //爲Bean讀取器設置Spring資源加載器,AbstractXmlApplicationContext的 //祖先父類AbstractApplicationContext繼承DefaultResourceLoader,所以,容器自己也是一個資源加載器 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); //爲Bean讀取器設置SAX xml解析器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. //當Bean讀取器讀取Bean定義的Xml資源文件時,啓用Xml的校驗機制 initBeanDefinitionReader(beanDefinitionReader); //Bean讀取器真正實現加載的方法 loadBeanDefinitions(beanDefinitionReader); }
能夠看到這裏經過建立Bean讀取器,最後調用loadBeanDefinitions實現定位、加載和註冊。loadBeanDefinitions方法的源碼以下:框架
//Xml Bean讀取器加載Bean定義資源 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //獲取Bean定義資源的定位 Resource[] configResources = getConfigResources(); if (configResources != null) { //Xml Bean讀取器調用其父類AbstractBeanDefinitionReader讀取定位 //的Bean定義資源 reader.loadBeanDefinitions(configResources); } //若是子類中獲取的Bean定義資源定位爲空,則獲取FileSystemXmlApplicationContext構造方法中setConfigLocations方法設置的資源 String[] configLocations = getConfigLocations(); if (configLocations != null) { //Xml Bean讀取器調用其父類AbstractBeanDefinitionReader讀取定位 //的Bean定義資源 reader.loadBeanDefinitions(configLocations); } }
接下來分析其父類AbstractBeanDefinitionReader是如何讀取定位Bean定義資源的,查看AbstractBeanDefinitionReader的loadBeanDefinitions方法,源碼以下:less
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { //獲取在IoC容器初始化過程當中設置的資源加載器 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 { //將指定位置的Bean定義資源文件解析爲Spring IOC容器封裝的資源 //加載多個指定位置的Bean定義資源文件 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); //委派調用其子類XmlBeanDefinitionReader的方法,實現加載功能 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. //將指定位置的Bean定義資源文件解析爲Spring IOC容器封裝的資源 //加載單個指定位置的Bean定義資源文件 Resource resource = resourceLoader.getResource(location); //委派調用其子類XmlBeanDefinitionReader的方法,實現加載功能 int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
能夠看到這裏最後委派調用其子類XmlBeanDefinitionReader的方法實現加載功能,XmlBeanDefinitionReader的loadBeanDefinitions方法源碼以下:
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { //將讀入的XML資源進行特殊編碼處理 return loadBeanDefinitions(new EncodedResource(resource)); } /** * Load bean definitions from the specified XML file. * @param encodedResource the resource descriptor for the XML file, * allowing to specify an encoding to use for parsing the file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ //這裏是載入XML形式Bean定義資源文件方法 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()); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { //將資源文件轉爲InputStream的IO流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //從InputStream中獲得XML的解析源 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //這裏是具體的讀取過程 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { //關閉從Resource中獲得的IO流 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(); } } }
查看doLoadBeanDefinitions方法,源碼以下:
//從特定XML文件中實際載入Bean定義資源的方法 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //將XML文件轉換爲DOM對象,解析過程由documentLoader實現 Document doc = doLoadDocument(inputSource, resource); //這裏是啓動對Bean定義解析的詳細過程,該解析過程會用到Spring的Bean配置規則 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); } }
這裏的registerBeanDefinitions方法即對Bean定義解析的詳細過程。
//按照Spring的Bean語義要求將Bean定義資源解析並轉換爲容器內部數據結構 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //獲得BeanDefinitionDocumentReader來對xml格式的BeanDefinition解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //得到容器中註冊的Bean數量 int countBefore = getRegistry().getBeanDefinitionCount(); //解析過程入口,這裏使用了委派模式,BeanDefinitionDocumentReader只是個接口, //具體的解析實現過程有實現類DefaultBeanDefinitionDocumentReader完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //統計解析的Bean數量 return getRegistry().getBeanDefinitionCount() - countBefore; }
這裏最後調用了DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法對xml文件的解析和註冊。源碼以下:
//根據Spring DTD對Bean的定義規則解析Bean定義Document對象 @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { //得到XML描述符 this.readerContext = readerContext; logger.debug("Loading bean definitions"); //得到Document的根元素 Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. //具體的解析過程由BeanDefinitionParserDelegate實現, //BeanDefinitionParserDelegate中定義了Spring Bean定義XML文件的各類元素 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; } } } //在解析Bean定義以前,進行自定義的解析,加強解析過程的可擴展性 preProcessXml(root); //從Document的根元素開始進行Bean定義的Document對象 parseBeanDefinitions(root, this.delegate); //在解析Bean定義以後,進行自定義的解析,增長解析過程的可擴展性 postProcessXml(root); this.delegate = parent; }
這裏主要分析觀察parseBeanDefinitions方法是如何解析配置文件的。源碼以下:
//使用Spring的Bean規則從Document的根元素開始進行Bean定義的Document對象 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //Bean定義的Document對象使用了Spring默認的XML命名空間 if (delegate.isDefaultNamespace(root)) { //獲取Bean定義的Document對象根元素的全部子節點 NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //得到Document節點是XML元素節點 if (node instanceof Element) { Element ele = (Element) node; //Bean定義的Document的元素節點使用的是Spring默認的XML命名空間 if (delegate.isDefaultNamespace(ele)) { //使用Spring的Bean規則解析元素節點 parseDefaultElement(ele, delegate); } else { //沒有使用Spring默認的XML命名空間,則使用用戶自定義的解//析規則解析元素節點 delegate.parseCustomElement(ele); } } } } else { //Document的根節點沒有使用Spring默認的命名空間,則使用用戶自定義的 //解析規則解析Document根節點 delegate.parseCustomElement(root); } }
能夠看到這裏有針對默認命名空間的解析過程,也有針對自定義命名空間的解析過程,這裏要注意的是針對非默認命名空間是經過NamespaceHandler的handler方法解析的(這裏在講解aop的時候會重點講),因此如今咱們來分析針對默認命名空間的解析過程parseDefaultElement方法,源碼以下:
//使用Spring的Bean規則解析Document元素節點 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //若是元素節點是<Import>導入元素,進行導入解析 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //若是元素節點是<Alias>別名元素,進行別名解析 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //元素節點既不是導入元素,也不是別名元素,即普通的<Bean>元素, //按照Spring的Bean規則解析元素 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
能夠看到的是這裏包括對<Import>導入元素、<Alias>別名元素、<Bean>元素的解析。下面對各個元素的解析進行分析,首先對導入元素的解析,方法importBeanDefinitionResource的源碼以下:
//解析<Import>導入元素,從給定的導入路徑加載Bean定義資源到Spring IoC容器中 protected void importBeanDefinitionResource(Element ele) { //獲取給定的導入元素的location屬性 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); //若是導入元素的location屬性值爲空,則沒有導入任何資源,直接返回 if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } // Resolve system properties: e.g. "${user.dir}" //使用系統變量值解析location屬性值 location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<>(4); // Discover whether the location is an absolute or relative URI //標識給定的導入元素的location是不是絕對路徑 boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { // cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:" //給定的導入元素的location不是絕對路徑 } // Absolute or relative? //給定的導入元素的location是絕對路徑 if (absoluteLocation) { try { //使用資源讀入器加載給定路徑的Bean定義資源 int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { // No URL -> considering resource location as relative to the current file. //給定的導入元素的location是相對路徑 try { int importCount; //將給定導入元素的location封裝爲相對路徑資源 Resource relativeResource = getReaderContext().getResource().createRelative(location); //封裝的相對路徑資源存在 if (relativeResource.exists()) { //使用資源讀入器加載Bean定義資源 importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } //封裝的相對路徑資源不存在 else { //獲取Spring IOC容器資源讀入器的基本路徑 String baseLocation = getReaderContext().getResource().getURL().toString(); //根據Spring IOC容器資源讀入器的基本路徑加載給定導入路徑的資源 importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]); //在解析完<Import>元素以後,發送容器導入其餘資源處理完成事件 getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); }
能夠看到這裏主要對路徑的解析,針對絕對路徑或者相對路徑調用XmlBeanDefinitionReader的loadBeanDefinitions方法進行BeanDefinition的解析定位,而且在解析完成以後發送容器導入其餘資源處理完成事件。
下面分析<Alias>別名元素的解析過程,processAliasRegistration方法的源碼以下:
//解析<Alias>別名元素,爲Bean向Spring IoC容器註冊別名 protected void processAliasRegistration(Element ele) { //獲取<Alias>別名元素中name的屬性值 String name = ele.getAttribute(NAME_ATTRIBUTE); //獲取<Alias>別名元素中alias的屬性值 String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; //<alias>別名元素的name屬性值爲空 if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } //<alias>別名元素的alias屬性值爲空 if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { //向容器的資源讀入器註冊別名 getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } //在解析完<Alias>元素以後,發送容器別名處理完成事件 getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } }
能夠看到這裏的解析過程比較簡單,分別去除bean名稱以及別名,而後向容器註冊別名,最後發送容器註冊別名處理完成事件。下面繼續分析對<Bean>元素的解析過程,processBeanDefinition源碼以下:
//解析Bean定義資源Document對象的普通元素 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); // BeanDefinitionHolder是對BeanDefinition的封裝,即Bean定義的封裝類 //對Document對象中<Bean>元素的解析由BeanDefinitionParserDelegate實現 // BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //向Spring IOC容器註冊解析獲得的Bean定義,這是Bean定義向IOC容器註冊的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. //在完成向Spring IOC容器註冊解析獲得的Bean定義以後,發送註冊事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
能夠看到這裏主要包括兩個過程,第一個是對節點的解析封裝,第二個是bean定義的註冊。咱們先看對節點的解析封裝,這裏的解析是委託給了BeanDefinitionParserDelegate的parseBeanDefinitionElement方法,源碼以下:
//解析Bean定義資源文件中的<Bean>元素,這個方法中主要處理<Bean>元素的id,name和別名屬性 @Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { //獲取<Bean>元素中的id屬性值 String id = ele.getAttribute(ID_ATTRIBUTE); //獲取<Bean>元素中的name屬性值 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); //獲取<Bean>元素中的alias屬性值 List<String> aliases = new ArrayList<>(); //將<Bean>元素中的全部name屬性值存放到別名中 if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; //若是<Bean>元素中沒有配置id屬性時,將別名中的第一個值賦值給beanName if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } //檢查<Bean>元素所配置的id或者name的惟一性,containingBean標識<Bean> //元素中是否包含子<Bean>元素 if (containingBean == null) { //檢查<Bean>元素所配置的id、name或者別名是否重複 checkNameUniqueness(beanName, aliases, ele); } //詳細對<Bean>元素中配置的Bean定義進行解析的地方 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { //若是<Bean>元素中沒有配置id、別名或者name,且沒有包含子元素 //<Bean>元素,爲解析的Bean生成一個惟一beanName並註冊 beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true); } else { //若是<Bean>元素中沒有配置id、別名或者name,且包含了子元素 //<Bean>元素,爲解析的Bean使用別名向IOC容器註冊 beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. //爲解析的Bean使用別名註冊時,爲了向後兼容 //Spring1.2/2.0,給別名添加類名後綴 String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } //當解析出錯時,返回null return null; }
能夠看到這裏的具體的解析過程交給了parseBeanDefinitionElement方法。
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { //記錄解析的<Bean> this.parseState.push(new BeanEntry(beanName)); //這裏只讀取<Bean>元素中配置的class名字,而後載入到BeanDefinition中去 //只是記錄配置的class名字,不作實例化,對象的實例化在依賴注入時完成 String className = null; //若是<Bean>元素中配置了parent屬性,則獲取parent屬性的值 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 { //根據<Bean>元素配置的class名稱和parent屬性值建立BeanDefinition //爲載入Bean定義信息作準備 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //對當前的<Bean>元素中配置的一些屬性進行解析和設置,如配置的單態(singleton)屬性等 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); //爲<Bean>元素解析的Bean設置description信息 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //對<Bean>元素的meta(元信息)屬性解析 parseMetaElements(ele, bd); //對<Bean>元素的lookup-method屬性解析 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //對<Bean>元素的replaced-method屬性解析 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析<Bean>元素的構造方法設置 parseConstructorArgElements(ele, bd); //解析<Bean>元素的<property>設置 parsePropertyElements(ele, bd); //解析<Bean>元素的qualifier屬性 parseQualifierElements(ele, bd); //爲當前解析的Bean設置所需的資源和依賴對象 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(); } //解析<Bean>元素出錯時,返回null return null; }
而後咱們分析註冊部分,源碼以下:
//將解析的BeanDefinitionHold註冊到容器中 public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. //獲取解析的BeanDefinition的名稱 String beanName = definitionHolder.getBeanName(); //向IOC容器註冊BeanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. //若是解析的BeanDefinition有別名,向容器爲其註冊別名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
接下來分析BeanDefinitionRegistry的registerBeanDefinition方法,這裏的BeanDefinitionRegistry是一個接口,最終由容器DefaultListableBeanFactory進行註冊,源碼以下:
//向IOC容器註冊解析的BeanDefiniton @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"); //校驗解析的BeanDefiniton 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 this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } //檢查是否有同名的BeanDefinition已經在IOC容器中註冊 if (oldBeanDefinition != null || containsSingleton(beanName)) { //重置全部已經註冊過的BeanDefinition的緩存 resetBeanDefinition(beanName); } }
能夠看到最終將bean定義註冊進了一個Map結構的beanDefinitionMap。
至此,IOC容器的初始化工做進行完畢,下篇會分析bean的後置處理器是如何工做的。