spring源碼淺析——IOC spring源碼淺析——IOC 學習資源分享

===========================================html

    原文連接: spring源碼淺析——IOC   轉載請註明出處!node

===========================================spring

在讀以前應該明白其重點:讀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對象。ide

  BeanDefinition:bean的全部信息在該對象中進行封裝,包括bean的參數值、方法名、是否懶加載、是否爲單例等各類信息post

  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操做進行彙總:

    一、AbstractApplicationContext中對resourcePatternResolver設值,並把自身當作resourceLoader設置給resourcePatternResolver。

    二、AbstractApplicationContext中對environment進行了設值

    三、把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) 操做進行彙總:

  一、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()彙總:
 *         一、讓子類進行自身特有的佔位符初始化操做
 *         二、驗證必須的配置參數是否已經加載
 */
    
//    進入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 加載分兩步:一、解析Document  二、註冊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

相關文章
相關標籤/搜索