===========================================
原文鏈接: spring源碼淺析——IOC 轉載請注明出處!
===========================================
在讀之前應該明白其重點:讀spring讀的不是其具體的技術實現,讀的是其系統層面的結構和設計! spring漂亮就漂亮在她的結構,包括接口和抽象類的靈活使用!
IOC模塊只是spring框架中的一個模塊,這里只對該模塊進行分析(使用版本:spring-framework-4.0.0.RELEASE-dist)。
IOC(Inversion of Control,控制反轉),“控制對象的創建或銷毀不再由調用處進行控制,而是由spring容器進行管理和控制”,“控制”就是指對程序中的對象實體的生命周期的控制。“反轉”本來是由調用處進行控制的,現在調用處不管了,反倒由spring進行管理,所以叫做bean的管理“反轉”了,合在一起也就是所謂的“控制反轉”。很不喜歡這四個字來描述!剛接觸spring的朋友對這個概念比較難以理解,我當時接觸的時候就感覺無法理解,直到后來一遍一遍的琢磨之后才理解其含義。
IOC涉及到的類比較多,結構較為復雜,在分析之前需要先抓住九個關鍵的類系(之所以用類系來形容是因為下面所列出來的不是某個具體的實現類,而是從接口到抽象類等一些系列相關類/接口):
BeanFactory:bean的管理工廠,所有的bean都在該對象中進行創建、存儲和銷毀。
DefaultListableBeanFactory:beanFactory具體實現類
Resource:spring的配置信息,該信息可能來源於xml文件,可能來源於網絡,也可能來源於數據流中。不管他從哪里來的,都封裝為Resource對象。
BeanDefinition:bean的所有信息在該對象中進行封裝,包括bean的參數值、方法名、是否懶加載、是否為單例等各種信息
BeanDefinitionReader:見名知意,構建BeanDefinition的reader,也就是通過該Reader從Resource中讀取信息封裝為BeanDefinition。
ApplicationContext:俗稱“上下文”和“控制反轉”一樣晦澀難懂,據我猜測之所以這樣命名,是因為context繼承了太多的接口,具有各種各樣的功能,可以稱為萬能的上帝。並且所有的需要用到的bean都可以在其中取到,起到溝通上下的橋梁的作用,所以叫做“上下文”。這里可以看出其特性是:實現了各種功能接口,封裝了各種bean對象。
Environment:運行環境配置信息,也就是一些配置屬性,來源於:properties文件,JVM properties,system環境變量,JNDI, servlet context parameters上下文參數,專門的Properties對象,Maps等等
Document:從xml文件文件中抽取出來的本文對象。
Element:從Document中取出的node節點
上面的描述暫時理解不了沒關系,只要心里面有這幾個模塊的概念就可以,在進行分析代碼的時候能夠意識到相關bean的功能即可,如需深入理解相關類系,需要深入對代碼進行剖析。
下面我們就從一個小例子進入對IOC模塊的分析。
Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="person" class="com.zpj.bean.Person"> <property name="name" value="xingoo" /> <property name="age" value="12" /> </bean> </beans>
程序入口
public class SpringTest { public static void main(String[] args) { //獲取context上下文對象,該上下文是ClassPathXmlApplicationContext類 ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml"); //從容器中取出名為"person"的對象 Person person = context.getBean("person", Person.class); //調用person.info()方法。 person.info(); } }
在進入ClassPathXmlApplicationContext構造方法之后,一直調用this()找到被重載的構造方法
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } //this()進入重載的構造方法 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
第一個super()一直向上找到AbstractApplicationContext,該類中實現了大部分的標准操作。
public AbstractApplicationContext(ApplicationContext parent) { this(); setParent(parent); } //先看this方法,this()進入該方法對resourcePatternResolver進行賦值 public AbstractApplicationContext() { this.resourcePatternResolver = getResourcePatternResolver(); } //這里需要注意的是getResourcePatternResolver()中返回的是PathMatchingResourcePatternResolver對象,並把this作為參數賦值給resolver中的resourceLoader。 protected ResourcePatternResolver getResourcePatternResolver() { return new PathMatchingResourcePatternResolver(this); } //在PathMatchingResourcePatternResolver中,this被賦值給resourceLoader。上面傳進來的是context,怎么用resourceLoader進行接收了呢? //因為Context實現了ResourceLoader的接口(這里需要記住) private final ResourceLoader resourceLoader;//resourceLoader的定義 public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) { Assert.notNull(resourceLoader, "ResourceLoader must not be null"); this.resourceLoader = resourceLoader; } //************************分析完this(),下面看setParent(parent);(這里parent是個null值,這里我們進入看看都進行了哪些操作)************************************************************** @Override public void setParent(ApplicationContext parent) { this.parent = parent; if (parent != null) { //注意這里,說明是從AbstractApplicationContext中取得的EnvEnvironment對象 Environment parentEnvironment = parent.getEnvironment(); if (parentEnvironment instanceof ConfigurableEnvironment) { //merge()對取得的parentEnvironment和當前的Environment進行合並。 getEnvironment().merge((ConfigurableEnvironment) parentEnvironment); } } } // 再AbstractApplicationContext中,如果存在則直接返回,如果不存在則進行創建操作 // 注意該方法,后面有多次進行獲取environment public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { //這里創建同時保存在了當前類AbstractApplicationContext中 this.environment = createEnvironment(); } return this.environment; } //創建的時候返回以StandardEnvironment實現類進行創建 protected ConfigurableEnvironment createEnvironment() { return new StandardEnvironment(); } // 至此,ClassPathXmlApplicationContext構造方法中super()的操作結束
這里對ClassPathXmlApplicationContext構造方法的super操作進行匯總:
1、AbstractApplicationContext中對resourcePatternResolver設值,並把自身當做resourceLoader設置給resourcePatternResolver。
2、AbstractApplicationContext中對environment進行了設值
3、把parent的environment和自己的environment進行了合並
這里需要注意的是,進行到這一步environment和resourcePatternResolver都已經有值了,在后面就可以進行get使用了。
下面進入到setConfigLocations(configLocations) 操作
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException { super(parent); //對該方法進行分析,這里configLocations的值為[springConfig.xml] setConfigLocations(configLocations); if (refresh) { refresh(); } } //進入void org.springframework.context.support.AbstractRefreshableConfigApplicationContext.setConfigLocations(String... locations) public void setConfigLocations(String... locations) { if (locations != null) { //這句斷言攢在的意義是什么?上面已經進行了不為空判斷,如果為null根本就執行不到這一步 Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i++) { //該方法主要目的就是對configLocations進行解析設值 this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } } // 進入resolvePath,這里調用了Environment的resolveRequiredPlaceholders方法(上面已經說過Environment已經進行了設值) protected String resolvePath(String path) { return getEnvironment().resolveRequiredPlaceholders(path); } // 該方法全名為:String org.springframework.core.env.AbstractEnvironment.resolveRequiredPlaceholders(String text) throws IllegalArgumentException //是實現在StandardEnvironment的父類AbstractEnvironment中 @Override public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException { // 這里又進行了調用 return this.propertyResolver.resolveRequiredPlaceholders(text); } // 這里的需要注意的是propertyResolver的實例化在哪里進行的。 // 在該類中有三個全局變量: protected final Log logger = LogFactory.getLog(getClass()); private final MutablePropertySources propertySources = new MutablePropertySources(this.logger); private final ConfigurablePropertyResolver propertyResolver =new PropertySourcesPropertyResolver(this.propertySources); // 所以propertyResolver在生成new StandEnvironment()的時候就同時創建了 // 這里不再繼續進行跟進去,this.propertyResolver.resolveRequiredPlaceholders(text);主要是對占位符進行了替換操作,把${name}替換為其實際值。 // 至此setConfigLocations()操作結束
這里對ClassPathXmlApplicationContext構造方法的setConfigLocations(configLocations) 操作進行匯總:
1、xml對配置文件名稱進行了解析,解析之后存儲在String[] org.springframework.context.support.AbstractRefreshableConfigApplicationContext.configLocations數組中。
到這一步,xml配置文件路徑已經進行了存儲,下面就該對xml進行讀取,加載、解析等操作。
下面進入到void org.springframework.context.support.AbstractApplicationContext.refresh() throws BeansException, IllegalStateException操作
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //對context的刷新進行准備操作 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //告訴子類刷新內部bean工廠 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //對beanFactory進行准備操作,以便於context的后續使用 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //在對beanFactory進行標准化處理之后,允許子類對beanFactory進行后處理操作,子類覆寫該方法進行特殊操作 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //在上下文中調用作為bean注冊的工廠處理器。 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //注冊攔截bean創建的bean處理器,這里只是進行注冊操作 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. //為上下文初始化message,即對國際化資源文件進行初始化 initMessageSource(); // Initialize event multicaster for this context. //初始化應用消息廣播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. //子類覆寫該方法,進行自己的初始化操作 onRefresh(); // Check for listener beans and register them. //查找所用已經注冊過的listener bean並注冊到廣播器中 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //初始化剩下的單實例(非惰性) finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //最后一步:完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent事件,通知其他監聽者 finishRefresh(); } catch (BeansException ex) { logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex); // Destroy already created singletons to avoid dangling resources. //發生異常銷毀已經創建的單利bean destroyBeans(); // Reset 'active' flag. //關閉刷新操作 cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
beanFactory的創建和初始化操作都在該方法中進行,下面逐個方法進行分析
// 進入void org.springframework.context.support.AbstractApplicationContext.prepareRefresh() protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment //留給子類覆寫,實現其特有的占位符初始化操作,這里方法體為空 initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties //驗證系統所必須的關鍵性配置參數是否已經加載到environment中,如果沒有則拋出MissingRequiredPropertiesException異常 getEnvironment().validateRequiredProperties(); } /** * void org.springframework.context.support.AbstractApplicationContext.prepareRefresh()匯總: * 1、讓子類進行自身特有的占位符初始化操作 * 2、驗證必須的配置參數是否已經加載 */ // 進入ConfigurableListableBeanFactory org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory() protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //刷新beanFactory refreshBeanFactory(); //獲取beanFactory並進行返回 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } //這里進行刷新操作,該方法實現於:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException @Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) {// 判斷方式:return (this.beanFactory != null); //如果已經存在則進行銷毀同時關閉,至於怎么銷毀和關閉的就不詳解 destroyBeans(); closeBeanFactory(); } try { //創建beanFactory,該方法直接return new DefaultListableBeanFactory(getInternalParentBeanFactory());這里需要注意的是beanFactory的實現類是DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); //設置序列化唯一id beanFactory.setSerializationId(getId()); //設置beanFactory相關屬性,是否允許覆蓋同名稱的不同定義的對象、是否允許循環依賴,可以被子類進行覆寫 customizeBeanFactory(beanFactory); //重點!!!加載beanDefinition 加載分兩步:1、解析Document 2、注冊BeanDefinition loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } // 這里進入關鍵方法loadBeanDefinitions,該方法實現於:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. //這里是使用xml文件進行配置的,所以這里使用的是XmlBeanDefinitionReader作為beanDefinitionReader, //這里beanFactory作為BeanDefinitionRegistry實例傳入beanDefinitionReader.XmlBeanDefinitionReader.XmlBeanDefinitionReader(BeanDefinitionRegistry registry); //注意beanDefinitionReader中的registry //提醒:還記得文章開始部分定義的BeanDefinition是什么嗎?bean的所有信息在該對象中進行封裝,包括bean的參數值、方法名、是否懶加載、是否為單例等各種信息 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); //注意這個ResourceLoader參數,此處的this指的是AbstractXmlApplicationContext,而AbstractBeanDefinitionReader.setResourceLoader(ResourceLoader resourceLoader)中接收的是ResourceLoader //所以說AbstractXmlApplicationContext實現了ResourceLoader接口(上面已經說過) beanDefinitionReader.setResourceLoader(this); //設置實體解析器,該ResourceEntityResolver還是用ResourceLoader接收的this beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. //對defintionReader進行初始化操作,運訓子類進行覆蓋,然后開始進行實際加載bean definition initBeanDefinitionReader(beanDefinitionReader); //重點!!!進行BeanDefinitions的加載操作 loadBeanDefinitions(beanDefinitionReader); } // 這里進入關鍵方法loadBeanDefinitions,該方法實現於:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //取得ClassPathResource並進行加載 Resource[] configResources = getConfigResources(); if (configResources != null) { //標識位置:loadBeanDefinitions_Resource reader.loadBeanDefinitions(configResources); } //取得ConfigLocations並進行加載(這里的ConfigLocations就是上面解析出來的String[] configLocations,存儲着配置文件的路徑) String[] configLocations = getConfigLocations(); if (configLocations != null) { //標識位置:loadBeanDefinitions_String reader.loadBeanDefinitions(configLocations); } } // 這里的loadBeanDefinitions_String和loadBeanDefinitions_Resource進行加載的方法是一樣的,都是調用int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException // 進行加載。只是loadBeanDefinitions_String在進行加載之前多了一步操作,把String轉化為Resource,然后進行加載,這里就從loadBeanDefinitions_String跟進去 // 進入loadBeanDefinitions方法,該方法實現於:int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException @Override public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { //循環對locations進行加載 counter += loadBeanDefinitions(location); } return counter; } //進入loadBeanDefinitions,該方法實現於:int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location) throws BeanDefinitionStoreException @Override public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { //繼續調用加載 return loadBeanDefinitions(location, null); } //進入loadBeanDefinitions,該方法實現於: int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { //還記得這個resourceLoader什么時候賦值的嗎?賦值的又是誰呢?AbstractXmlApplicationContext ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } //這里根據resourceLoader進行划分,不同的resourceLoader從不同的源加載resource。 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) { //把resource進行緩存 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. //只能加載從絕對URL加載單例資源,xml走的是這里,進入之后區分類路徑資源、URL資源和文件系統資源(xml屬於該種),這里不再對封裝resource進行分析 Resource resource = resourceLoader.getResource(location); //進行記載definition,這里調用的方法和標識位置:loadBeanDefinitions_Resource調用的加載方法就相同了 int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { //把resource進行緩存 actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } } //進入loadBeanDefinitions,該方法實現於:int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException //當前進行加載的resources存儲於這個ThreadLocal線程局部變量中 private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded"); 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<EncodedResource>(4); //操作之前先把currentResources放在resourcesCurrentlyBeingLoaded中,注意下面加載操作完成之后進行了remove this.resourcesCurrentlyBeingLoaded.set(currentResources); } //這里把encodedResource放進currentResources中,后面依舊會remove if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { //獲取inputStream InputStream inputStream = encodedResource.getResource().getInputStream(); try { //封裝為InputSource InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { //為inputSource設置resource的編碼方式 inputSource.setEncoding(encodedResource.getEncoding()); } //這里才是真正進行BeanDefinitions的加載操作,前面的都是進行預處理封裝inputSource return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { //操作之后把currentResources從resourcesCurrentlyBeingLoaded中移除出去,注意上面加載操之前的add currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } // 進入doLoadBeanDefinitions,該方法實現於:int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //關鍵方法兩步:取得Document;注冊BeanDefinition //這里就不再解析怎么加載Document的了,Spring是使用SAX進行xml解析的,可以自己詳細了解 Document doc = doLoadDocument(inputSource, resource); //把BeanDefinition注冊到context中 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,該方法實現於: int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //創建documentReader這里返回的是 return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(this.getEnvironment()); //這個countBefore是為了統計從Document中加載的beanDefinition的個數 int countBefore = getRegistry().getBeanDefinitionCount(); //進行注冊BeanDefinition操作 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } // 進入registerBeanDefinitions,該方法實現於:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext) public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); //取出root節點,從root節點遍歷所有節點進行注冊 doRegisterBeanDefinitions(root); } // 進入doRegisterBeanDefinitions,該方法實現於:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element 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 parent = this.delegate; this.delegate = createDelegate(this.readerContext, root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { Assert.state(this.environment != null, "Environment must be set for evaluating profiles"); String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!this.environment.acceptsProfiles(specifiedProfiles)) { return; } } } //為子類預留,覆寫進行解析之前的特殊操作 preProcessXml(root); //通過代理進行解析 parseBeanDefinitions(root, this.delegate); //為子類預留,覆寫進行解析之后的特殊操作 postProcessXml(root); this.delegate = parent; } // 進入postProcessXml,該方法實現於:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 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)) { //循環所有的Element節點進行解析 parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } // 進入postProcessXml,該方法實現於: void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 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”標簽進行解析注冊,這里從這里面進去分析,這里的分支思路大同小異 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //對“beans”標簽進行解析注冊 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } } // 進入processBeanDefinition,該方法實現於: void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //對ele進行解析,把id、name、aliases進行封裝 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //如果需要則使用bdHolder的代理進行操作 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //對definition的最終注冊,注意該方法的第二個參數:Registry //設置readerContext位置:documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //設置Registry位置(第五個參數this):return new XmlReaderContext(resource, this.problemReporter, this.eventListener,this.sourceExtractor, this, getNamespaceHandlerResolver()); //該this指代的是XmlBeanDefinitionReader實例 //而他的Registry設置位置是:XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); //所以該Registry就是beanFactory BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. //發送注冊event給監聽者 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } // 進入BeanDefinitionReaderUtils.registerBeanDefinition,該方法實現於: void org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException { // Register bean definition under primary name. //取得beanName注冊beanDefinition String beanName = definitionHolder.getBeanName(); //注冊beanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. //取得對該beanName注冊aliases,這里關聯的是aliases--beanName,所以通過aliase進行取值的時候需要先由aliase找到beanName,然后根據beanName找到beanDefinition String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } } // 進入registerBeanDefinition.registerBeanDefinition,該方法實現於:void org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException //注意該方法的實現位置:DefaultListableBeanFactory private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64); @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; //加鎖同步 //注意該上面的beanDefinitionMap synchronized (this.beanDefinitionMap) { oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { //如果已經存在該beanDefinition則判斷是否允許覆蓋 if (!this.allowBeanDefinitionOverriding) { 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 (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { //如果不存在該bean則注冊beanName this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } //把bean加入緩存beanDefinitionMap,這里完成注冊 this.beanDefinitionMap.put(beanName, beanDefinition); } if (oldBeanDefinition != null || containsSingleton(beanName)) { //重置該beanDefinition的所有緩存 Reset all bean definition caches for the given bean resetBeanDefinition(beanName); } } //至此,beanFactory構建完成, ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();結束。
beanFactory創建完成之后,緩存中已經存儲有配置bean的beanDefinition。
在void org.springframework.context.support.AbstractApplicationContext.refresh() throws BeansException, IllegalStateException中的其他方法是對beanFactory以及context的其他操作,主要是為子類覆寫一些方法、注冊一些監聽、處理一下國際化資源文件等,這里就不再進行詳細分析。
至此,該方法中的context 創建完成。
public class SpringTest { public static void main(String[] args) { //獲取context上下文對象,該上下文是ClassPathXmlApplicationContext類 ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml"); //從容器中取出名為"person"的對象 Person person = context.getBean("person", Person.class); //調用person.info()方法。 person.info(); } }
spring用着方便,但是實現起來確實很復雜,里面涉及了大量的設計模式,裝飾模式、代理模式、工廠模式、模板方法等,對於學習系統設計有很大的幫助。
文章中只簡單的介紹了一下beanFactory的創建,其中忽略了大量的細節,比如對單利bean的管理,beanDefinition到bean的創建,此外,對beanFactory的后期處理,Listeners的添加、MessageSource的初始化等。有興趣的朋友可以深入研究一下,這里就不再繼續分析,能力有限,很多東西我也不是太明白,還需要繼續學習。建議剛接觸該模塊源碼的朋友一定要多進行debug讀源碼,對源碼進行分析,如果能在熟練使用sping的基礎上讀源碼效果會更好,最好自己親自繪制一下該模塊的類圖,這樣可以對該模塊的整體結構有一個比較清晰的認識,對上面的九個關鍵的類系就能夠有更好的理解。
在學習的過程中遇到一本講解比較詳細的書,這里分享給大家,里面還有繪制的相關類圖,用powerdesigner進行打開。
鏈接在此:學習資源分享 文件名分別為:spring源碼深度解析 spring-IOC相關類圖
------over