Spring学习06--IOC实现原理以及IOC容器初始化过程

一、IOC原理
Spring功能如此强大,但是再强大的功能也是用java代码写出来的,那么就来看看IOC的实现原理是什么。
上一章说到,由于bean中lazy-init属性的存在,我们没有办法一次性将所有bean全部实例化,并且放到一个Map

package org.springframework.beans.factory.support;

import java.io.NotSerializableException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Provider;

import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @author Costin Leau
 * @since 16 April 2001
 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    private static Class javaxInjectProviderClass = null;

    static {
        ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
        try {
            javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - Provider interface simply not supported then.
        }
    }


    /** Map from serialized id to factory instance */
    private static final Map> serializableFactories =
            new ConcurrentHashMap>();

    /** Optional id for this factory, for serialization purposes */
    private String serializationId;

    /** Whether to allow re-registration of a different definition with the same name */
    private boolean allowBeanDefinitionOverriding = true;

    /** Whether to allow eager class loading even for lazy-init beans */
    private boolean allowEagerClassLoading = true;

    /** Resolver to use for checking if a bean definition is an autowire candidate */
    private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();

    /** Map from dependency type to corresponding autowired value */
    private final Map resolvableDependencies = new HashMap();

    /** Map of bean definition objects, keyed by bean name */
    private final Map beanDefinitionMap = new ConcurrentHashMap();

    /** List of bean definition names, in registration order */
    private final List beanDefinitionNames = new ArrayList();

    /** Whether bean definition metadata may be cached for all beans */
    private boolean configurationFrozen = false;

    /** Cached array of bean definition names in case of frozen configuration */
    private String[] frozenBeanDefinitionNames;


}

果不其然,是它是它就是它。

/** Map of bean definition objects, keyed by bean name */
private final Map beanDefinitionMap = new ConcurrentHashMap();

和我们设想的是一样的,这个实现类里面定义了这样一个Map,看注释,bean的name值作为这个Map的key值,所以,我们需要哪个bean,就从这个map里面找就行了。

这里,IOC容器的原理就清晰很多了,只要把配置文件里面的bean标签按照规则读取出来,然后以name为key,BeanDefinition对象为value值存放在这个map中,当我们getBean时,实际上就是从这个map中取一个对象的过程,那么IOC容器的原理可以总结为:
1、需要一个File对象指向我们的xml配置文件,也就是说,我们需要找到xml文件的具体位置,也叫资源定位。
2、需要一个Reader读取我们的xml文件,把bean标签一个个读取出来,也叫DOM解析
3、将读取出来的bean标签放到一个Map当中
说实话,看到这里,Spring在我心中那神秘又伟岸的形象瞬间崩塌了,这特么也不见得很高级啊。回过头想想,再牛逼的技术也是有简简单单的东西组合实现的。继续说。

既然已经知道了IOC的原理,我们就可以自己来做一个获取bean的过程了。
首先来个测试类:

public class User {

    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

配置文件:

<bean id="user" class="com.errol.dao.User">
    <property name="name">
        <value>宝宝value>
    property>
bean>

测试类:

public class Client {

    @Test
    public void testFactory(){
        /*
         * 下面使用的都是Spring的类或者接口
         */
        //资源定位
        ClassPathResource cr = new ClassPathResource("applicationContext.xml");
        //bean工厂
        DefaultListableBeanFactory db = new DefaultListableBeanFactory();
        //解析xml的工具
        XmlBeanDefinitionReader xd = new XmlBeanDefinitionReader(db);
        //解析xml并且存放到map
        xd.loadBeanDefinitions(cr);
        System.out.println("bean的个数:"+db.getBeanDefinitionCount());
        User user = (User)db.getBean("user");
        System.out.println(user);

    }
}

输出结果:

log4j:WARN No appenders could be found for logger (org.springframework.core.CollectionFactory).
log4j:WARN Please initialize the log4j system properly.
bean的个数:1
com.errol.dao.User@900bac2

成功!
接下来,联想一下平时我们用的ApplicationContext对象去获取bean时候的用法

ApplicationContext applicationContext = new ClassPathXMLApplicationContext("applicationContext");
User user = new applicationContext .getBean("user");

我们四步做完的事情,上面一步就解决了,new ClassPathXMLApplicationContext(“applicationContext”);这句话里面到底做了什么呢?

二、IOC容器初始化过程
我们来看看ClassPathXMLApplicationContext这个方法里面到底有什么猫腻,把我们四步实现变成了一步。进入这个方法看一看:

public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent)
            throws BeansException {

        super(parent);
        this.configLocations = configLocations;
        refresh();
}

里面就调用了一个refresh方法,在进去看看,进入到AbstracApplicationContext的一个抽象类中,ClassPathXmlApplicationContext就是继承自这个抽象类,只不过中间还有两层,AbstractXmlApplicationContext和AbstractRefreshableApplicationContext两个抽象类。

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            this.startupTime = System.currentTimeMillis();

            synchronized (this.activeMonitor) {
                this.active = true;
            }

            // Tell subclass to refresh the internal bean factory.
            refreshBeanFactory();
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();

            // Tell the internal bean factory to use the context's class loader.
            beanFactory.setBeanClassLoader(getClassLoader());

            // Populate the bean factory with context-specific resource editors.
            beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this));

            // Configure the bean factory with context semantics.
            beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
            beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
            beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
            beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
            beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered with the context instance.
            for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {
                BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
                factoryProcessor.postProcessBeanFactory(beanFactory);
            }

            if (logger.isInfoEnabled()) {
                if (getBeanDefinitionCount() == 0) {
                    logger.info("No beans defined in application context [" + getDisplayName() + "]");
                }
                else {
                    logger.info(getBeanDefinitionCount() + " beans defined in application context [" + getDisplayName() + "]");
                }
            }

            try {
                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors();

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors();

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate singletons this late to allow them to access the message source.
                beanFactory.preInstantiateSingletons();

                // Last step: publish corresponding event.
                publishEvent(new ContextRefreshedEvent(this));
            }

            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                beanFactory.destroySingletons();
                throw ex;
            }
        }
    }

这里面主要看refreshBeanFactory方法,但是这个抽象类中没有实现,来找找它的子类,上面说的几个,一个个看过去,在
AbstractRefreshableApplicationContext抽象类中,有这个方法的实现,来看一下:

protected final void refreshBeanFactory() throws BeansException {
        // Shut down previous bean factory, if any.
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory != null) {
                this.beanFactory.destroySingletons();
                this.beanFactory = null;
            }
        }

        // Initialize fresh bean factory.
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            loadBeanDefinitions(beanFactory);

            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
            if (logger.isInfoEnabled()) {
                logger.info("Bean factory for application context [" + getDisplayName() + "]: " + beanFactory);
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException(
                    "I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
        }
    }

上面的实现,我们熟悉的东西出现了:DefaultListableBeanFactory beanFactory,这不就是上面我们用四步的中的一步吗,创建这个DefaultListableBeanFactory 的实例对象,然后后面就是解析DOM,将bean标签解析成BeanDefinition对象,放到Map中,来看看,这里是不是这么实现的,进去loadBeanDefinitions方法,发现这里也没实现,往子类找,AbstractXmlApplicationContext中对这个方法有了实现,进去看一下:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

熟悉的东西XmlBeanDefinitionReader,读取资源文件中的bean定义,initBeanDefinitionReader方法在这个类中没有实现,按照字面意思就是初始化我们的beanDefinitionReader,关键是后面那个方法loadBeanDefinitions(beanDefinitionReader);这不就是我们写的四步中的一步么,只是它经过了层层封装,用一步就能搞定我们要做的事情,那么来看看XmlBeanDefinitionReader中这个方法loadBeanDefinitions是如何实现的就完成摸透了IOC的初始化过程 。。。。。的一半了。

三、loadBeanDefinitions方法详解
顺着我们的源码一直往下找,在org.springframework.beans.factory.xml.XmlBeanDefinitionReader这个类中,找到了loadBeanDefinitions方法的实现:

    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 currentResources = this.resourcesCurrentlyBeingLoaded.get();  
        if (currentResources == null) {  
            currentResources = new HashSet(4);  
            this.resourcesCurrentlyBeingLoaded.set(currentResources);  
        }  
        if (!currentResources.add(encodedResource)) {  
            throw new BeanDefinitionStoreException(  
                    "Detected recursive loading of " + encodedResource + " - check your import definitions!");  
        }  
        //这里得到XML文件,并得到IO的InputSource准备进行读取。  
        try {  
            InputStream inputStream = encodedResource.getResource().getInputStream();  
            try {  
                InputSource inputSource = new InputSource(inputStream);  
                if (encodedResource.getEncoding() != null) {  
                    inputSource.setEncoding(encodedResource.getEncoding());  
                }  
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());  
            }  
            finally {  
                inputStream.close();  
            }  
        }  
        catch (IOException ex) {  
            throw new BeanDefinitionStoreException(  
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);  
        }  
        finally {  
            currentResources.remove(encodedResource);  
            if (currentResources.isEmpty()) {  
                this.resourcesCurrentlyBeingLoaded.set(null);  
            }  
        }  
    }

里面主要关注一下doLoadBeanDefinitions方法,这个方法是具体的读取bean的详细过程:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  
            throws BeanDefinitionStoreException {  
        try {  
            int validationMode = getValidationModeForResource(resource);  
            //这里取得XML文件的Document对象,这个解析过程是由 documentLoader完成的,这个documentLoader是DefaultDocumentLoader,在定义documentLoader的地方创建  
            Document doc = this.documentLoader.loadDocument(  
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());  
            //这里启动的是对BeanDefinition解析的详细过程,这个解析会使用到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,这个方法里面就是详细的解析过程了。顺着这个方法下去,找到了接口BeanDefinitionDocumentReader,接口中没有实现,看看子类DefaultBeanDefinitionDocumentReader,有这个方法的实现

    /**
     * Parses bean definitions according to the "spring-beans" DTD.
     * 

Opens a DOM Document; then initializes the default settings * specified at <beans> level; then parses * the contained bean definitions. */ public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); preProcessXml(root); parseBeanDefinitions(root, delegate); postProcessXml(root); }

再次定位到一个方法parseBeanDefinitions,再进去:

/** 
     * Parse the elements at the root level in the document: 
     * "import", "alias", "bean". 
     * @param root the DOM root element of the document 
     */  
    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)) {  
                  // 解析import, alias, beans等默认标签  
                        parseDefaultElement(ele, delegate);  
                    }  
                    else {  
                  // 解析aop, mvc, dubbo等自定义标签,这部分在文末解释  
                        delegate.parseCustomElement(ele);  
                    }  
                }  
            }  
        }  
        else {  
            delegate.parseCustomElement(root);  
        }  
    }  

这里需要说明的一点是:关于具体的Spring BeanDefinition的解析,是在BeanDefinitionParserDelegate中完成的。这个类里包含了各种Spring Bean定义规则的处理,感兴趣的同学可以仔细研究。我们举一个例子来分析这个处理过程,比如我们最熟悉的对Bean元素的处理是怎样完成的,也就是我们在XML定义文件中出现的这个最常见的元素信息是怎样被处理的。在这里,我们会看到那些熟悉的BeanDefinition定义的处理,比如id、name、aliase等属性元素。把这些元素的值从XML文件相应的元素的属性中读取出来以后,会被设置到生成的BeanDefinitionHolder中去。这些属性的解析还是比较简单的。对于其他元素配置的解析,比如各种Bean的属性配置,通过一个较为复杂的解析过程,这个过程是由parseBeanDefinitionElement来完成的。解析完成以后,会把解析结果放到BeanDefinition对象中并设置到BeanDefinitionHolder中去。

在BeanDefinitionParserDelegate类中的这个方法,这里只贴了部分代码,太多了,是对bean标签详细解析过程,看返回值,是一个AbstractBeanDefinition 的实例,也就是说,解析出来就是BeanDefinition对象。

/**
     * Parse the bean definition itself, without regard to name or aliases. May return
     * null if problems occured during the parse of the bean definition.
     */
    public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, BeanDefinition containingBean) {

        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE);
        }
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

说到这里,我们再来理一下:
1、BeanDefinitionParserDelegate解析bean标签,生成一个AbstractBeanDefinition 对象
2、生成的AbstractBeanDefinition 对象放到了BeanDefinitionHolder对象中
3、BeanFactory对象调用registerBeanDefinition方法,将BeanDefinitionHolder中的AbstractBeanDefinition 对象注册到****Map当中去。这就与上面的逻辑连接通了。

我们举一个对property进行解析的例子来完成对整个BeanDefinition载入过程的分析,还是在类BeanDefinitionParserDelegate的代码中,它对BeanDefinition中的定义一层一层地进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会封装成PropertyValue对象并设置到BeanDefinition对象中去,如以下代码清单所示。

/** 
 * 这里对指定bean元素的property子元素集合进行解析。 
 */  
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {  
    //遍历所有bean元素下定义的property元素  
    NodeList nl = beanEle.getChildNodes();  
    for (int i = 0; i < nl.getLength(); i++) {  
        Node node = nl.item(i);  
        if (node instanceof Element && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) {  
            //在判断是property元素后对该property元素进行解析的过程  
            parsePropertyElement((Element) node, bd);  
        }  
    }  
}  
public void parsePropertyElement(Element ele, BeanDefinition bd) {  
    //这里取得property的名字  
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);  
    if (!StringUtils.hasLength(propertyName)) {  
        error("Tag 'property' must have a 'name' attribute", ele);  
        return;  
    }  
    this.parseState.push(new PropertyEntry(propertyName));  
    try {  
        //如果同一个bean中已经有同名的存在,则不进行解析,直接返回。也就是说,如果在同一个bean中有同名的property设置,那么起作用的只是第一个。  
        if (bd.getPropertyValues().contains(propertyName)) {  
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  
            return;  
        }  
        //这里是解析property值的地方,返回的对象对应对Bean定义的property属性设置的解析结果,这个解析结果会封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中去。  
        Object val = parsePropertyValue(ele, bd, propertyName);  
        PropertyValue pv = new PropertyValue(propertyName, val);  
        parseMetaElements(ele, pv);  
        pv.setSource(extractSource(ele));  
        bd.getPropertyValues().addPropertyValue(pv);  
    }  
    finally {  
        this.parseState.pop();  
    }  
}  
/** 
 * 这里取得property元素的值,也许是一个list或其他。 
 */  
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {  
    String elementName = (propertyName != null) ?  
                    " element for property '" + propertyName + "'" :  
                    " element";  

    // Should only have one child element: ref, value, list, etc.  
    NodeList nl = ele.getChildNodes();  
    Element subElement = null;  
    for (int i = 0; i < nl.getLength(); i++) {  
        Node node = nl.item(i);  
        if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT) &&  
                !DomUtils.nodeNameEquals(node, META_ELEMENT)) {  
            // Child element is what we're looking for.  
            if (subElement != null) {  
                error(elementName + " must not contain more than one sub-element", ele);  
            }  
            else {  
                subElement = (Element) node;  
            }  
        }  
    }  
    //这里判断property的属性,是ref还是value,不允许同时是ref和value。  
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);  
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);  
    if ((hasRefAttribute && hasValueAttribute) ||  
            ((hasRefAttribute || hasValueAttribute) && subElement != null)) {  
        error(elementName +  
                " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);  
    }  
    //如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息。  
    if (hasRefAttribute) {  
        String refName = ele.getAttribute(REF_ATTRIBUTE);  
        if (!StringUtils.hasText(refName)) {  
            error(elementName + " contains empty 'ref' attribute", ele);  
        }  
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);  
        ref.setSource(extractSource(ele));  
        return ref;  
    } //如果是value,创建一个value的数据对象TypedStringValue ,这个对象封装了value的信息。  
    else if (hasValueAttribute) {  
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));  
        valueHolder.setSource(extractSource(ele));  
        return valueHolder;  
    } //如果还有子元素,触发对子元素的解析  
    else if (subElement != null) {  
        return parsePropertySubElement(subElement, bd);  
    }  
    else {  
        // Neither child element nor "ref" or "value" attribute found.  
        error(elementName + " must specify a ref or value", ele);  
        return null;  
    }  
}  

上面提到了对ref属性的解析,同时提到了一个类RuntimeBeanReference,这个类实现自BeanReference,这个接口很简单,就一个方法String getBeanName();这个接口存储的就是bean与bean之间的依赖关系,就比如ref标签,在property对象中,就是ref指向一个BeanReference引用,这个引用中对应的就是依赖的那个bean的信息,通过getBeanName就能获取到那个bean的名称,也就能获取到BeanDefinition对象了。

经过这样一层一层的解析,我们在XML文件中定义的BeanDefinition就被整个给载入到了IoC容器中,并在容器中建立了数据映射。在IoC容器中建立了对应的数据结构,或者说可以看成是POJO对象在IoC容器中的映像,这些数据结构可以以AbstractBeanDefinition为入口,让IoC容器执行索引、查询和操作。

上面我们贴了一小段.BeanDefinitionParserDelegate类代码的开头,定义的是bean的一些属性,其实下面都有对应属性的解析方法,上面贴的只是对Property属性的解析过程。

在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions中,上面提到的对一些默认的属性,调用的是BeanDefinitionParserDelegate的parseCustomElement,如果不是默认的标签,比如自定义的,注解,还有AOP的,将调用另一个方法parseCustomElement,这个逻辑也是相对复杂,涉及到后面的内容,这里暂时不作解析,后面再补上来。

总结一下IOC的原理:
1、IOC的核心就是容器的初始化,首先我们定义一个容器,都是BeanFactory接口的实现类
2、容器进行初始化,调用的的refreshBeanFactory()方法进行初始化。
3、初始化的过程主要包括,读取xml配置文件
4、将每一个bean标签通过BeanDefinitionParserDelegate的parseDefaultElement或者parseCustomElement方法读取出来,并且存放到AbstractBeanDefinition对象中
5、将AbstractBeanDefinition对象再保存到BeanDefinitionHolder对象中
6、BeanFactory中有一个Map

你可能感兴趣的:(java,spring,ioc)