Spring之IoC容器解析(一)

2 篇文章 0 订阅

Spring之IoC容器解析(一)


  • 简介
  • 层级示意图&接口功能介绍
  • 原理分析
  • 小结

1. 简介

IoC作为Spring的核心功能之一,内部继承体系错综复杂,下面我们来对它剥丝抽茧的分析一波。
首先,从整体上看Spring容器可以分为两大部分:外部容器和内部容器。外部容器指的是ApplicationContext接口的实现类,我们写程序时也可能经常会用到它。内部容器是BeanFactory的实现类,内部调用较多。

2. 层级示意图

1.内部容器层级示意图

pub-sub

位于顶层的HierarchicalBeanFactory,AutowireCapableBeanFactory,ListableBeanFactory接口均继承于BeanFactory。

ok,那大致介绍下这些接口完成或者扩展了什么功能。

1.BeanFactory:定义了最基础的获取bean的方法,以及一些bean的匹配操作(单例模式,类型匹配等)。

2.HierarchicalBeanFactory:扩展了BeanFactory,提供了获取双亲BeanFactory的方法。其实就是让你可以有一个父BeanFactory

3.ListableBeanFactory:同样扩展了BeanFactory,它可以列举出所有bean的实例而非通过客户端给出的bean name一个一个搜索。感觉预加载的时候比较有用。

4.AutowireCapableBeanFactory:从接口定义的方法中可以看出,该接口主要用于自动装配bean,包括创建bean、装配bean的属性、装配bean的依赖、注册bean等一整套流程。该接口对于外部的应用程序而言,几乎不需要使用,其只应用于Spring容器的内部管理,实际上只有内部BeanFactory实现此功能。

5.ConfigurableBeanFactory:提供bean的属性配置功能,需要对bean进行配置的BeanFactory都会实现它。

6.ConfigurableListableBeanFactory:相比于上面,它可以修改bean definition,以及它可以提前实例化以单例模式存在的bean。

7.AbstractBeanFactory:BeanFactory的一个抽象基类,提供了对bean的基本操作。

8.AbstractAutowireCapableBeanFactory:与上面最主要的区别就是实现了默认的bean创建方法createBean()。

9.DefaultListableBeanFactory:第一个可以真正直接拿来用的容器。官方释义,在访问bean前,先注册所有的definition(可能从bean definition配置文件中)。使用预先建立的bean定义元数据对象,从本地的bean definition表(其实就是一个map)中查询bean definition因而将不会花费太多成本。

10.SingletonBeanRegistry:提供单例注册,查询服务。

11.DefaultSingletonBeanRegistry:实现单例与DisposableBean的生命周期管理(创建,维护,销毁)

12.FactoryBeanRegistrySupport:添加工厂方式创建类FactoryBean的支持。

2.外部容器层级示意图

out-container
相比于直接扩展自BeanFactory的简单容器,那么实现自ApplicationContext的容器可以称之为高级容器。同时,在以下方面的功能有所加强。

1.支持应用事件,该功能源于ApplicationEventPublisher接口。引入事件机制后,便于bean的管理。
2.资源访问,该特性源于Resource,ResourceLoader。以此,我们可以从不同的地方来获取bean信息。
3.支持不同的信息源,该接口这里没有标出,是源自MessageSource,可以支持国际化,为多语言版本的应用提供支持。

那还是大致介绍一下这些接口以及抽象类的基本功能。

1.ApplicationContext: 首先是一个外部容器的中心接口,提供应用程序的配置。根据官方释意:一个ApplicationContext提供如下功能:

·用来访问应用程序组件的bean factory方法,其继承自ListableBeanFactory。
·能以通用的方式加载文件资源,其继承自ResourceLoader。
·能够向注册的监听器发布事件,其继承自ApplicationEventPublisher。
·能够解析消息,支持国际化,继承自MessageSource。
·继承自父上下文,后代上下文中的Definition将总能获得优先级,这意味着,例如,一个单亲上下文能够被整个应用程序使用,而每个servlet有它自己的孩子上下文,它独立于其他的servlet。

2.ConfigurableApplicationContext:配置和生命周期方法被封装在这里。

3.AbstractApplicationContext:ApplicationContext的基本抽象实现,提供了BeanFactory的后置processor的注册、应用上下文的双亲维护、资源加载的功能。

4.AbstractRefreshableApplicationContext:官方释义,ApplicationContext的基类的实现,其支持多次refreshs,每次创建一个内部bean工厂实例。通常(但不一定),一个上下文将会由一系列的配置定位来驱动,加载bean definations。

5.AbstractRefreshableConfigApplicationContext:主要为配置文件位置的设置提供入口,即实现了setConfigLocation方法。这就提供了不依赖于Spring的且更灵活、通用的配置注入方式。

6.AbstractXmlApplicationContext:ApplicationContext的便利基类的实现。用于提取包含bean definition信息的XML文档,该文档由XmlBeanDefinitionReader负责解释。

7.FileSystemXmlApplicationContext:这是一个简单的,一站式的便利的ApplicationContext的基本实现。

8.ResourceLoader:加载资源(类路径和文件路径)的策略接口,ApplicationContext需要提供此功能来加载资源。

9.ResourcePatternResolver:解释位置模式的策略接口,其扩展自ResourcePatternResolver接口。

3.原理分析

1.内部容器的启动及加载过程
/*
* 可以看到XmlBeanFactroy的代码还是比较简单的,只是初始化了一个用于读取XML形式的BeanDefinition的对象,除此之外并没有太多的操作。
* 因为主要的BeanFactory的基本实现都已经在DefaultListableBeanFactory中完成了。
*/
public class XmlBeanFactory extends DefaultListableBeanFactory {

    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }

}

以上可以看出XmlBeanFactory本身并没有做什么,真正扩展的是XmlBeanDefinitionReader,因为它需要去读取XML形式的BeanDefinition,而BeanFactory的基本功能都在DefaultListableBeanFactory中实现了,XmlBeanFactory直接继承过来。
在初始化父容器的过程中,没有什么特别的。
来看下XmlBeanDefinitionReader如何读取BeanDefinition。

//这个的资源形式是要以Resource形式给出的,比如:
//ClassPathResource res = new ClassPathResource("bean.xml");
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
    }

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());
        }
//这里开始没搞明白,为什么用一个ThreadLocal,不过currentResources这个Set应该是用来判断资源是否循环加载的。
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
        //获取目标资源经spring包装后的IO流
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                //进行bean加载的入口
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
        //这里remove掉了之前刚加载好的资源应用,因为resourcesCurrentlyBeingLoaded这个东西的意义应该是当前正在被加载的资源,所以,资源加载完后,会从Set中remove掉。
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

在分析doLoadBeanDefinitions()之前,还有其他部分细节在这里说下。比如Set currentResources = this.resourcesCurrentlyBeingLoaded.get(),为何要用ThreadLocal来存这个Set,根据final代码块的执行过程,推测出该Set应该是保存了即将要被加载或者正在被加载的资源。而loadBeanDefinitions()也没用进行额外的多线程安全的控制,所以借助于ThreadLocal,使得如果存在多线程共同加载,那么,各个线程加载各自的资源,避免出现预期被加载的资源在多线程环境下被其他线程覆盖的情况。
那继续说doLoadBeanDefinitions()

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
        //使用标准的JAXP配置的xml解析器从Resource中加载到Document。这里就不展开说明XML内容加载到Document的过程了。
            Document doc = doLoadDocument(inputSource, resource);
            //根据加载的Document注册Bean definition。
            return registerBeanDefinitions(doc, resource);
        }
        catch
        ...

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //根据Document的实际类型创建对应的Reader,将Document中的内容读取到BeanDefinition中。
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //获取已注册的bean definition数量
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        //返回从resource中成功注册的bean definition数量
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

关于BeanDefinition的载入要分为两步,一是讲XML的内容解析到Document,二是讲Document中的内容按照Spring的规定解析成bean。第一步是在DefaultDocumentLoader中完成的,第二步在BeanDefinitionDocumentReader中完成。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
        doRegisterBeanDefinitions(root);
    }

    //从root结点开始解析,将每一个bean都进行注册
    protected void doRegisterBeanDefinitions(Element root) {
    //实际上真正的解析过程是在BeanDefinitionParserDelegate这个代理中(processBeanDefinition)进行的。
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);
//判断XML中的命名空间是否是默认值(http://www.springframework.org/schema/beans)
//命名空间是Spring用来区分bean元素与其他元素。举个例子,比如A1扩展Spring定义了一个元素名为B的元素,A2同样的定义了一个元素名为B的元素,如果没有命名空间加以区分,那Spring是无法将这两个元素区分开来的。
        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)) {
                    return;
                }
            }
        }
        //空函数体,可由开发中重写,在真正解析Document前执行
        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        //同preProcessXml(root)
        postProcessXml(root);

        this.delegate = parent;
    }

    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;
                    //只有在默认命名空间下的元素的会被SpringIoC容器解析
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //BeanDefinition的封装,若成功返回Holder,则说明解析成功
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // 将BeanDefinition注册到容器中
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

BeanDefinitionHolder是BeanDefinition的一个封装,除了包括BeanDefinition之外,还有beanName,aliases(别名)等信息。具体的解析过程在BeanDefinitionParserDelegate中的parseBeanDefinitionElement处执行。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    //获取bean定义中的id,name,aliase等属性
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List<String> aliases = new ArrayList<String>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        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");
            }
        }

        if (containingBean == null) {
        //检查bean的name唯一性,通过一个存有name的Set以及一个存有aliase的Set来进行判断
            checkNameUniqueness(beanName, aliases, ele);
        }
        //对bean的详细解析入口
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    ...
    }

    public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));

        //读取了bean的className,载入到BeanDefinition中,但是没有实例化!
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }

        try {
            String parent = null;
            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                parent = ele.getAttribute(PARENT_ATTRIBUTE);
            }
            //生成所需的BeanDefinition
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            //根据XML中定义的内容,对BeanDefinition进行设置。
            //包括singleton,lazy-init,autowire,autowire-candidate等等,基本包含了Spring XML的所有属性
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //解析其对应的描述信息(description)
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            //添加元数据信息
            parseMetaElements(ele, bd);
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析构造函数所需参数
            parseConstructorArgElements(ele, bd);
            //解析bean的一些成员属性,例如map,list,set等
            parsePropertyElements(ele, bd);
            //解析bean的访问限定符
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            return bd;
        }
        catch ...
        return null;
    }

比如,来看一个解析List的成员的过程

public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {
//获取value的类型
        String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
        //获取List的元素个数
        NodeList nl = collectionEle.getChildNodes();
        ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
        target.setSource(extractSource(collectionEle));
        target.setElementTypeName(defaultElementType);
        target.setMergeEnabled(parseMergeAttribute(collectionEle));
        parseCollectionElements(nl, target, bd, defaultElementType);
        return target;
    }

    protected void parseCollectionElements(
            NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
//遍历所有元素结点,判断类型是否为Element
        for (int i = 0; i < elementNodes.getLength(); i++) {
            Node node = elementNodes.item(i);
            if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
                target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
            }
        }
    }

纵观整个BeanDefinition的载入过程,从XML到Resource,从Resource到Document,从Document到最后的BeanDefinition,最复杂也最重要的,当属最后一步。
从XML到Resource,其实只是从IO流读取一个文件。
从Resource到Document,是按照通用的XML解析方式解析从Resource获得的数据。
从Document到最后的BeanDefinition,需要根据Spring对于bean的规范,将Document中每个对应的bean结点解析出来。这其实是一个比较漫长的过程,我们知道在用XML形式定义的bean中,Spring特有的标签名有好几十个(ref,idref,scope,props…),需要一个一个去判断这些结点名存在与否,在进行相应的解析。我感觉解析过程中比较麻烦的是关于property的解析,这里说麻烦倒也不是说过程麻烦,而是除却基本的数据类型,像List,Map,Set这样的类型,解析他们的函数基本一样,只有一行代码不一样,但又不能使用泛型方法,所以看上去重复的代码量有点多。
BeanDefinition是一个接口,对应于Spring XML配置的标签项,它定义了一系列的函数来设置,获取这些标签值,可以认为它是bean的一个抽象表现,一般用RootBeanDefinition或者ChildBeanDefinition来实现就可以了。
而BeanDefinitionHolder是BeanDefinition的一个封装,同时持有bean的name,aliases(别名)以及BeanDefinition的实例,是在一个bean标签被成功解析后返回的一个Holder。
加载过程告一段落了,继续讲注册的过程。

//仍旧是DefaultBeanDefinitionDocumentReader类

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//从Document中加载到BeanDefinition
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
            //注册BeanDefinition
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // 获取bean的name,因为最终注册后是以map的形式来维护bean的
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // 如果有别名的话,同样为这些别名与bean构建映射关系
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

来看下bean是如何被注册的。先说明下BeanDefinition默认是在DefaultListableBeanFactory中被注册的。那么也就是说,在DefaultListableBeanFactory中有维护BeanDefinition的对象。

//用beanname与BeanDefinition产生映射关系,以此维护
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
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 {
            //验证BeanDefinition是否合法构建,主要是检验需要override的方法是否按照规定override
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;
//先从map中取一下,看该bean是否已经被注册。
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
        //如果该bean不允许被重写,则会抛出异常
            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()) {
            //Role有三种,ROLE_APPLICATION(0),ROLE_SUPPORT(1),ROLE_INFRASTRUCTURE(2),进入该分支意味着,BeanDefinition的Role会被改变
                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 + "]");
                }
            }
            //发出一个警告,告知BeanDefinition会被一个新的不同的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 + "]");
                }
            }
            //允许重写该BeanDefinition
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            //把BeanDefinition放到map中去,算是完成注册
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
        //检查该factory的bean创建是否开始了
            if (hasBeanCreationStarted()) {
            //注册过程需要保持数据的一致性,所以用synchronized加锁
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    //新注册一个BeanDefinition,所以list长度+1,它所持有的是所有bean的name
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    //如果单例模式的bean名单中有该bean的name,那么移除掉它。
                    //意味着,将一个原本是单例模式的bean重新注册成一个普通的bean
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // 仍处于启动阶段,bean还没有开始注册
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
        //做的其实是清除key = beanName 的缓存。
        //因为oldBeanDefinition如果存在,且执行到了这里也没有抛出异常,说明该BeanDefinition已经被覆盖,缓存需要更新。
        //若是单例模式的bean对象Set中包含该beanName,执行到这里说明该BeanDefinition已经从一个单例模式的bean变为了一个普通的bean,所以缓存也需要更新
            resetBeanDefinition(beanName);
        }
    }

到这里,BeanDefinition的注册就完成了一大半了,剩下的部分就是把该BeanDefinition对应的aliases(别名)也分别注册进去,同样也是用一个map来维护,其中key为beanName,value为aliase,这里就不给出代码了。
这里简单说明几个问题:

1.为何hasBeanCreationStarted()为true时,需要进行同步?
先看下hasBeanCreationStarted()做了什么。

// 存的是那些至少被创建了一次的bean的name
private final Set<String> alreadyCreated =
            Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));
protected boolean hasBeanCreationStarted() {
//判断的条件是这个Set是否为空。
        return !this.alreadyCreated.isEmpty();
    }

//要知道他什么时候为空,我觉得可以先去看下它什么是后不为空,也就是什么时候进行add操作

//该函数在AbstractBeanFactory中,只有在doGetBean(...)中出现过,该操作是将BeanDefinition实例化成想要的bean
protected void markBeanAsCreated(String beanName) {
        if (!this.alreadyCreated.contains(beanName)) {
            this.alreadyCreated.add(beanName);
            clearMergedBeanDefinition(beanName);
        }
    }

这样也就明确了只有某个bean被实例化后,alreadyCreated集合才有可能不为空。
根据Spring容器初始化的顺序,会先实例化所有的单例模式的bean,按道理讲,实例化后的alreadyCreated一般不为空。但是上面讲的是内部容器,也就是BeanFactory这一分支,不涉及ApplicationContext分支。

 public static void main(String[] args) {
        Resource resource = new ClassPathResource("beans.xml");
        BeanFactory factory = new XmlBeanFactory(resource);
        boolean s = factory.containsBean("mybean");
        }

就像上面这样使用的话,整个流程就是:

加载xml---->解析xml到Document---->解析Document到BeanDefinition---->注册BeanDefinition(知道这个流程后,自己也能写个简单的IoC容器)
并不像外部容易初始化那般复杂。所以该问题留到讲外部容器初始化过程的时候再继续讨论

4.小结

XmlBeanFactory而言,它扩展于DefaultListableBeanFactory,一般的,这种情况下只需要实现该BeanFactory对应的资源读取器Reader,而注册及其他部分,在DefaultListableBeanFactory中已经完成了。
实际上,DefaultListableBeanFactory就是作为Spring内部默认实际使用的BeanFactory而存在的。
对于内部容器初始化,过程并不复杂。就如同上面提到的一样,流程很简单,但是部分操作(bean的注册,BeanDefinition的生成)与外部容器的初始化都是通用的,所以值得关注。尤其是BeanDefinition生成的时候,Spring解析的及其详细,包括作用范围,重写的函数,各种类型成员的解析等等,一个bean所能表示的所有的信息都被解析到BeanDefinition中。


理解有误之处,请大家多多指正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值