Spring之IoC容器解析(一)

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中。


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

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
最近有很多人微信底部的变色卡片导航是怎么做的,我在网上看了好几个例子,都是效果接近,都存有一些差异,自己琢磨也做了一个,几乎99%的还原,效果还不错吧 仔细观察微信图片,发现他有两部分内容,外面的边框和里面的内容,内容的颜色由绿变为透明,这部分可以直接改变透明度,外面的边框,颜色在灰色和绿色之间变化,就不能简单的改变透明度了,ImageView的tint 为我们提供了可行方案,tint可以为图标着色,既可以在xml中,也可以在代码中设置,一共有16中模式,分别为 在xml中设置:直接添加tint属性,选择
这一篇主要介绍Bitmap相关的一些优化技术,包括加载图片,图片内存管理,图片缓存。 加载图片 图片缩放 我们在加载图片的时候,经常会遇到OOM的问题,也许我们测试的时候图片比较小,但是实际上使用的图片可能 会很大,我最好的方式就是在加载的时候就把图片缩小。Options提供了inJustDecodeBounds来先获取图片的大小, 如下代码: BitmapFactory .Options options = new BitmapFactory .Options () ; options .inJustD

Doze流程代码注释 - 2016-06-14 14:06:26

终于把Idle流程大致理解清楚了。先贴出这个类,自己的一些理解注释都写上了。后续有时间,更新流程小结。 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may ob
什么是流式布局呢?也不知道哪个高手把它称之为流失布局,叫什么不重要,重要的是要知道怎么实现,今天就实现下这个功能,先看下图什么就知道是什么是流式布局了,做过电商的app或者网购的人都知道有一个什么选择规格(x,xl,ml)so, 当然这个用其他什么gridview也能实现,如果大小是一样的话,如果大小不一样就不好搞定了,那么如果使用今天讲的流式布局就很好做了,那么还是一开始并不是直接讲这个效果怎么实现,而是把相关的技术点尽自己的能力讲清楚,如果这个懂了,说不定不仅这个流式布局懂了,也许你还懂了其他东西,这
原创文章,转载请注明:转载自 Keegan小钢 并标明原文链接: http://keeganlee.me/post/android/20150916 微信订阅号: keeganlee_me 写于2015-09-16 Android样式的开发:shape篇 Android样式的开发:selector篇 Android样式的开发:layer-list篇 Android样式的开发:drawable汇总篇 Android样式的开发:View Animation篇 Android样式的开发:Property Ani

通讯录的原型实现(-) - 2016-06-14 14:06:54

相信大部分在拥有第一部手机的时候,干的第一件事情都是将一些你以前记录在笔记本或者同学录里面的手机号记录到手机的通讯录里面,没错今天我们就要讲到手机通讯录原型的实现步骤,当然也借鉴了网上的一些资源,只不过还是记录一下具体的实现步骤和逻辑思维实现步骤,方便以后用到的时候又到网上到处胡乱搜索还要去看别人的毫无注释的代码(PS本人非常不喜欢看一些别人写的没有注释的代码)。废话不多说,先上图,来点视觉效果。                           左侧为进入应用的默认显示图,右侧为输入内容之后搜索的结果
今天用Jenkins+iOS+fir+蒲公英 搭建持续集成环境,把过程记录一下。 第一步:安装Jenkins 方法一:直接去官网下载安装包 下载地址: http://jenkins-ci.org/ 下载后直接点击进入安装 安装完成后在Terminal中输入命令,打开Jenkins: open /Applications/Jenkins/jenkins.war 方法二:使用命令行安装 1.安装 home-brew(安装指导) ruby -e “$(curl -fsSL https://raw.githubu

Android初级教程人品计算器 - 2016-06-14 14:06:31

先看布局: main_activity.xml LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:co

RxJava操作符(07-辅助操作) - 2016-06-14 14:06:30

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51658445 本文出自: 【openXu的博客】 目录: Delay Do MaterializeDematerialize ObserveOnSubscribeOn TimeInterval Timeout Timestamp Using To 源码下载 1. Delay   delay的意思就是延迟,这个操作符会延迟一段指定的时间再发射Observable的数据。 RxJava的实现是 dela
在之前的博文中已经讲到,小区专用参考信号的基本映射单位是RE(参考博文《 LTE下行物理层传输机制(1)-天线端口Antenna Port和小区特定参考信号CRS 》),PCFICH信道的基本映射单位是REG(参考博文《 LTE下行物理层传输机制(2)-PCFICH信道和资源组REG 》),PHICH信道的基本映射单位也是REG(参考博文《 LTE下行物理层传输机制(3)-PHICH信道 》),而本文所提到的 PDCCH 信道,它的基本映射单位则是 CCE 。 1.CCE的组成 CCE,全称 Contro