Spring源码解析之一 ------ 默认标签的解析注册(IOC的第一步)

来源:互联网 发布:阿里云监控系统 编辑:程序博客网 时间:2024/06/07 23:20

要看Spring bean加载的过程,最好的是Debug跟着流程走,有所侧重的看。首先需要的搭建本地环境和简单的项目工程,搭建的方法我放在这篇博客里。

http://blog.csdn.net/weililansehudiefei/article/details/73744017

我也是看了不少博客,Debug了很多次才终于理解整个过程。第一次看的时候,别心急,几天看完第一次都没关系。

我相信这篇文章,能让你看懂bean加载。


一、schema、xsd的认识

我们在xml里面配置bean的时候,一定会在xml的开始有类似如下的定义

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"       xsi:schemaLocation="http://www.springframework.org/schema/beans                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd                        http://www.springframework.org/schema/context                        http://www.springframework.org/schema/context/spring-context-3.1.xsd                        http://www.springframework.org/schema/tx                        http://www.springframework.org/schema/tx/spring-tx.xsd">    <bean id="userId" name="userName" class="com.heitian.ssm.model.User"></bean></beans>

可以看到整个xml是被<beans></beans>标签给封起来的,在<beans>里面定义了schcema。它由URI + LOCATION构成。比如上面的文件中,

http://www.springframework.org/schema/beans                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
前面的http://www.springframeword.org/shema/beans表示URI,后面的表示xsd文件的地址,xsd文件是描述相应的标签的。比如这里的spring-beans-3.1.xsd就是描述bean这个标签的定义和组成。具体的讲解会在下一部分,实现自定义标签时候讲解。现在知道就行。当然spring并不是直接就去xsd文件的链接去下载相应的xsd,而是先去本地找。在本地的spring.shemas文件中,有对应的本地地址关系

http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsdhttp\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsdhttp\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsdhttp\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsdhttp\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsdhttp\://www.springframework.org/schema/beans/spring-beans-4.0.xsd=org/springframework/beans/factory/xml/spring-beans-4.0.xsdhttp\://www.springframework.org/schema/beans/spring-beans-4.1.xsd=org/springframework/beans/factory/xml/spring-beans-4.1.xsdhttp\://www.springframework.org/schema/beans/spring-beans-4.2.xsd=org/springframework/beans/factory/xml/spring-beans-4.2.xsdhttp\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-4.2.xsdhttp\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsdhttp\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsdhttp\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsdhttp\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsdhttp\://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsdhttp\://www.springframework.org/schema/tool/spring-tool-4.0.xsd=org/springframework/beans/factory/xml/spring-tool-4.0.xsdhttp\://www.springframework.org/schema/tool/spring-tool-4.1.xsd=org/springframework/beans/factory/xml/spring-tool-4.1.xsdhttp\://www.springframework.org/schema/tool/spring-tool-4.2.xsd=org/springframework/beans/factory/xml/spring-tool-4.2.xsdhttp\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-4.2.xsdhttp\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsdhttp\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsdhttp\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsdhttp\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsdhttp\://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsdhttp\://www.springframework.org/schema/util/spring-util-4.0.xsd=org/springframework/beans/factory/xml/spring-util-4.0.xsdhttp\://www.springframework.org/schema/util/spring-util-4.1.xsd=org/springframework/beans/factory/xml/spring-util-4.1.xsdhttp\://www.springframework.org/schema/util/spring-util-4.2.xsd=org/springframework/beans/factory/xml/spring-util-4.2.xsdhttp\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-4.2.xsd

二、spring中bean的解析和注册

首先,因为我们是在ClassPath下xml文件的方式配置的,所以Debug后会进入ClassPathXmlApplicationContext中,

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {        this(new String[]{configLocation}, true, (ApplicationContext)null);    }

然后会调用同类中的多态的构造方法,如下。configLocations就是我们配置的xml文件的地址

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {        super(parent);        this.setConfigLocations(configLocations);        if(refresh) {            this.refresh();        }    }


在这里,通过this.setConfigLocations(configLocations)方法,设置此次bean加载的配置文件位置。

然后进入到了refresh()方法。但从代码看,貌似进入的refresh()方法还是在ClassPathXmlApplicationContex里面,但是并不是。因为

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext 
因为继承关系,这个时候,进入的是AbstractXmlApplicationContext中的refresh()方法。下面这个图,说明了接下来整个程序的调用图。其实核心代码并不多,但是在去往核心代码之前,会做一系列的准备和校验以及相应数据的转换。


进入到refresh()方法,可以看到这里包含了bean的主要处理逻辑。而我们要进入的是this.obtainFreshBeanFactory()。

    public void refresh() throws BeansException, IllegalStateException {        Object var1 = this.startupShutdownMonitor;        synchronized(this.startupShutdownMonitor) {            this.prepareRefresh();            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();            this.prepareBeanFactory(beanFactory);            try {                this.postProcessBeanFactory(beanFactory);                this.invokeBeanFactoryPostProcessors(beanFactory);                this.registerBeanPostProcessors(beanFactory);                this.initMessageSource();                this.initApplicationEventMulticaster();                this.onRefresh();                this.registerListeners();                this.finishBeanFactoryInitialization(beanFactory);                this.finishRefresh();            } catch (BeansException var9) {                if(this.logger.isWarnEnabled()) {                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);                }                this.destroyBeans();                this.cancelRefresh(var9);                throw var9;            } finally {                this.resetCommonCaches();            }        }    }

进入到obtainFreashBeanFactory方法,然后进入this.refreshBeanFactory();在refreshBeanFactory中,Spring创建了一个beanFactory,

然后进入loadBeanDefinitions(beanFactory)。

    protected final void refreshBeanFactory() throws BeansException {        if(this.hasBeanFactory()) {            this.destroyBeans();            this.closeBeanFactory();        }        try {            DefaultListableBeanFactory beanFactory = this.createBeanFactory();            beanFactory.setSerializationId(this.getId());            this.customizeBeanFactory(beanFactory);            this.loadBeanDefinitions(beanFactory);  //这里进入            Object var2 = this.beanFactoryMonitor;            synchronized(this.beanFactoryMonitor) {                this.beanFactory = beanFactory;            }        } catch (IOException var5) {            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);        }    }

在loadBeanDefinitions中,Spring为该beanFactory创建了一个beanDefinitionReader,看名字也知道这个reader是用来读取bean的定义信息。

然后进入this.loadBeanDefinitions(beanDefinitionReader)

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);        beanDefinitionReader.setEnvironment(this.getEnvironment());        beanDefinitionReader.setResourceLoader(this);        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));        this.initBeanDefinitionReader(beanDefinitionReader);        this.loadBeanDefinitions(beanDefinitionReader);//进入这里    }
进入之后,是如下的内容。在这里判断configResource是否为空,同时把第一步设置的configLocations,通过get方法读了出来,也就是配置文件spring.xml的地址和名字。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {        Resource[] configResources = this.getConfigResources();        if(configResources != null) {            reader.loadBeanDefinitions(configResources);        }        String[] configLocations = this.getConfigLocations();        if(configLocations != null) {            reader.loadBeanDefinitions(configLocations);//进入这里        }    }

连续进入loadBeanDefinition后,如图。这个时候在进入新的loadBeanDefinition之前,他会根据location的位置,获取Resource。

    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {        ResourceLoader resourceLoader = this.getResourceLoader();        if(resourceLoader == null) {            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");        } else {            int loadCount;            if(!(resourceLoader instanceof ResourcePatternResolver)) {                Resource resource = resourceLoader.getResource(location);                loadCount = this.loadBeanDefinitions((Resource)resource);                if(actualResources != null) {                    actualResources.add(resource);                }                if(this.logger.isDebugEnabled()) {                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");                }                return loadCount;            } else {                try {                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);                    loadCount = this.loadBeanDefinitions(resources);//进入这里                    if(actualResources != null) {                        Resource[] var6 = resources;                        int var7 = resources.length;                        for(int var8 = 0; var8 < var7; ++var8) {                            Resource resource = var6[var8];                            actualResources.add(resource);                        }                    }                    if(this.logger.isDebugEnabled()) {                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");                    }                    return loadCount;                } catch (IOException var10) {                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);                }            }        }    }
接下来进入进入后,resource文件被转成了encodedResource,

var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
这个方法是真正做事情的方法。凡是看到以do开头,那说明是真正做事情的。之前的都是各种转换和准备。需要说明的是,从resource到encodedResource再到inoputStream再到

inputSource,这时候xml文件并没有真正读取。如果你是debug,可以看到这几个里面存放的都是spring.xml的加载路径。

进入真正的方法。

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {        Assert.notNull(encodedResource, "EncodedResource must not be null");        if(this.logger.isInfoEnabled()) {            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());        }        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();        if(currentResources == null) {            currentResources = new HashSet(4);            this.resourcesCurrentlyBeingLoaded.set(currentResources);        }        if(!((Set)currentResources).add(encodedResource)) {            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");        } else {            int var5;            try {                InputStream inputStream = encodedResource.getResource().getInputStream();                try {                    InputSource inputSource = new InputSource(inputStream);                    if(encodedResource.getEncoding() != null) {                        inputSource.setEncoding(encodedResource.getEncoding());                    }                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource()); //这里do开头的方法,才是做事情的方法                } finally {                    inputStream.close();                }            } catch (IOException var15) {                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);            } finally {                ((Set)currentResources).remove(encodedResource);                if(((Set)currentResources).isEmpty()) {                    this.resourcesCurrentlyBeingLoaded.remove();                }            }            return var5;        }    }
进入后,我们发现通过inputSource和resource生成了doc对象,在doLoadDocument方法里,进行了文档的解析。文档解析的过程也有一些需要注意的地方,但是这里我们先不管它,进入registerBeanDefinitions(doc,resource)。

   protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {        try {            Document doc = this.doLoadDocument(inputSource, resource);            return this.registerBeanDefinitions(doc, resource);        } catch (BeanDefinitionStoreException var4) {            throw var4;        } catch (SAXParseException var5) {            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);        } catch (SAXException var6) {            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);        } catch (ParserConfigurationException var7) {            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);        } catch (IOException var8) {            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);        } catch (Throwable var9) {            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);        }    }

进入后,定义了一个BeanDefiniDocumReader,这个documentReader用来读取doc对象,并注册bean。

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();        int countBefore = this.getRegistry().getBeanDefinitionCount();        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));//进入        return this.getRegistry().getBeanDefinitionCount() - countBefore;    }


进去以后,获取元素的根节点root,Debug的时候,可以看到这个root的name属性正是beans。这和我们一开始说的,整个xml文档是被<beans></beans>包起来的说法一致。

然后进入doRegisterBeanDefinitons(root)。

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {        this.readerContext = readerContext;        this.logger.debug("Loading bean definitions");        Element root = doc.getDocumentElement();        this.doRegisterBeanDefinitions(root);//进入    }
进入之后,如下图,这个时候我们继续进入注释表明的地方。

    protected void doRegisterBeanDefinitions(Element root) {        BeanDefinitionParserDelegate parent = this.delegate;        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);        if(this.delegate.isDefaultNamespace(root)) {            String profileSpec = root.getAttribute("profile");            if(StringUtils.hasText(profileSpec)) {                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");                if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {                    return;                }            }        }        this.preProcessXml(root);        this.parseBeanDefinitions(root, this.delegate);//进入        this.postProcessXml(root);        this.delegate = parent;    }

进入parseBeanDefinitions后,这里开始对Document对象里面的Element节点root,开始遍历解析。

Spring的默认标签会进入this.parseDefaultElement解析,我们自定义的标签会进入delegate.parseCustomElement解析。

自定义标签的解析,在另外一篇单独讲解。这里讲解spring自带标签的解析。

    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)) {                        this.parseDefaultElement(ele, delegate);//进入                    } else {                        delegate.parseCustomElement(ele);                    }                }            }        } else {            delegate.parseCustomElement(root);        }    }

进入之后,可以看到spring默认的标签只有四个:import、alias、bean、beans。在我们的spring.xml里面,我们只定义了root节点beans和一个子节点bean,所以进入bean的解析方法。

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {        if(delegate.nodeNameEquals(ele, "import")) {            this.importBeanDefinitionResource(ele);        } else if(delegate.nodeNameEquals(ele, "alias")) {            this.processAliasRegistration(ele);        } else if(delegate.nodeNameEquals(ele, "bean")) {            this.processBeanDefinition(ele, delegate);  //进入        } else if(delegate.nodeNameEquals(ele, "beans")) {            this.doRegisterBeanDefinitions(ele);        }    }
进入之后 如下,先获取了bean标签的 BeanDefinitionHolder,这个bdHolder是什么呢?我们知道bean标签里面,有name、id、class等属性,这个方法就是为了获取ele标签的属性。如果你想直接进入最终bean的注册地方,可以跳过下面橙色的地方。

我们先进入解析生成BeanDefinitionHolder的方法里,然后再回到核心的registerBeanDefinition。

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);        if(bdHolder != null) {            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//进入            try {                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());//核心            } catch (BeanDefinitionStoreException var5) {                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);            }            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));        }    }

进入这个,

        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

看标签的属性是怎么生成的,相应的注释直接写在里面了。

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {        String id = ele.getAttribute("id");//获取id属性,userId        String nameAttr = ele.getAttribute("name");//获取name属性,userName        List<String> aliases = new ArrayList(); //别名,我们自己在bean中配置的name,属于别名        if(StringUtils.hasLength(nameAttr)) {            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");            aliases.addAll(Arrays.asList(nameArr));        }        String beanName = id;  //beanName是由id属性给的,而不是name属性        if(!StringUtils.hasText(id) && !aliases.isEmpty()) {            beanName = (String)aliases.remove(0);            if(this.logger.isDebugEnabled()) {                this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");            }        }        if(containingBean == null) {            this.checkNameUniqueness(beanName, aliases, ele);        }        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);//进入        if(beanDefinition != null) {            if(!StringUtils.hasText(beanName)) {                try {                    if(containingBean != null) {                        beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);                    } else {                        beanName = this.readerContext.generateBeanName(beanDefinition);                        String beanClassName = beanDefinition.getBeanClassName();                        if(beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {                            aliases.add(beanClassName);                        }                    }                    if(this.logger.isDebugEnabled()) {                        this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");                    }                } catch (Exception var9) {                    this.error(var9.getMessage(), ele);                    return null;                }            }            String[] aliasesArray = StringUtils.toStringArray(aliases);            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);        } else {            return null;        }    }

接下来进入this.parseBeanDefinitionElement中,在这个方法里,传入了beanName先被保存起来。然后获取class属性。

在this.createBeanDefinition中,通过反射获取class属性的类,然后保存在bd中。下方的注释说明了主要的作用,希望能进去看一下。

    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {        this.parseState.push(new BeanEntry(beanName));        String className = null;        if(ele.hasAttribute("class")) {            className = ele.getAttribute("class").trim();        }        try {            String parent = null;            if(ele.hasAttribute("parent")) {                parent = ele.getAttribute("parent");            }            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);//反射获取class属性指定的类,保存该类和类名            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);//获取ele标签的所有属性,即bean的所有属性。            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));            this.parseMetaElements(ele, bd);            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());            this.parseConstructorArgElements(ele, bd);            this.parsePropertyElements(ele, bd);            this.parseQualifierElements(ele, bd);            bd.setResource(this.readerContext.getResource());            bd.setSource(this.extractSource(ele));            AbstractBeanDefinition var7 = bd;            return var7;        } catch (ClassNotFoundException var13) {            this.error("Bean class [" + className + "] not found", ele, var13);        } catch (NoClassDefFoundError var14) {            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);        } catch (Throwable var15) {            this.error("Unexpected failure during bean definition parsing", ele, var15);        } finally {            this.parseState.pop();        }        return null;    }


上面一部分一下bdHolder的作用。

你需要知道的是bdHolder里面保存着该标签的所有属性。

然后回到正题,进入标签的注册阶段,这里就是bean标签的注册阶段。

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
进入这个方法,
    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {        String beanName = definitionHolder.getBeanName();//获取bean的名字,userId        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//注册的核心        String[] aliases = definitionHolder.getAliases();        if(aliases != null) {            String[] var4 = aliases;            int var5 = aliases.length;            for(int var6 = 0; var6 < var5; ++var6) {                String alias = var4[var6];                registry.registerAlias(beanName, alias);            }        }    }
进入注册的核心registerBeanDefinition(...),终于到最终的注册方法上了。可能你之前也听过,容器其实是一个map,这里你将会看到它。
   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 var9) {                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);            }        }        BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);//从容器beanDefinitionMap中获取beanName对应的value        if(oldBeanDefinition != null) {//如果不是null,说明该beanName已经在容器中存在了,抛异常            if(!this.isAllowBeanDefinitionOverriding()) {                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");            }            if(oldBeanDefinition.getRole() < beanDefinition.getRole()) {                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(!beanDefinition.equals(oldBeanDefinition)) {                if(this.logger.isInfoEnabled()) {                    this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");                }            } else if(this.logger.isDebugEnabled()) {                this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");            }            this.beanDefinitionMap.put(beanName, beanDefinition);        } else {//创建bean            if(this.hasBeanCreationStarted()) {                Map var4 = this.beanDefinitionMap;   //存储bean的容器                synchronized(this.beanDefinitionMap) {                    this.beanDefinitionMap.put(beanName, beanDefinition);                     List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);                    updatedDefinitions.addAll(this.beanDefinitionNames);                    updatedDefinitions.add(beanName);                    this.beanDefinitionNames = updatedDefinitions;                    if(this.manualSingletonNames.contains(beanName)) {                        Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);                        updatedSingletons.remove(beanName);                        this.manualSingletonNames = updatedSingletons;                    }                }            } else {                this.beanDefinitionMap.put(beanName, beanDefinition);//将bean注册到容器中                this.beanDefinitionNames.add(beanName);                this.manualSingletonNames.remove(beanName);            }            this.frozenBeanDefinitionNames = null;        }        if(oldBeanDefinition != null || this.containsSingleton(beanName)) {            this.resetBeanDefinition(beanName);        }    }

上面就是核心的注册功能,在完成注册后,程序回到下面的地方.注册完bean后,开始进行别名alias的处理。这里还是有需要说道的地方,可别因为看到了核心的注册,后面别名这里
就不看了。进入下面注释说明的registerAlias()
    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {        String beanName = definitionHolder.getBeanName();        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//注册bean        String[] aliases = definitionHolder.getAliases();        if(aliases != null) {            String[] var4 = aliases;            int var5 = aliases.length;            for(int var6 = 0; var6 < var5; ++var6) {                String alias = var4[var6];                registry.registerAlias(beanName, alias);//进入            }        }    }

进入后,代码如下。name就是beanName,在我的配置文件里就是userId,alias就是在配置文件里定义的name属性的值,也就是userName.我特意将id和name属性用不同的
名称,就是为了这里。
    public void registerAlias(String name, String alias) {        Assert.hasText(name, "'name' must not be empty");//name也就是 id属性的value:userId        Assert.hasText(alias, "'alias' must not be empty");alias也就是配置文件中name属性的value:userName        if(alias.equals(name)) {//id和name属性的值一样,就从存放别名的map中删除。            this.aliasMap.remove(alias);        } else {            String registeredName = (String)this.aliasMap.get(alias);            if(registeredName != null) {                if(registeredName.equals(name)) {                    return;                }                if(!this.allowAliasOverriding()) {                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");                }            }            this.checkForAliasCircle(name, alias);            this.aliasMap.put(alias, name);//将alisas(userName) 和 name(userId)存入别名map        }    }


到这里,整个流程基本就讲解完了。有疑问或者错误,欢迎留言。





































阅读全文
1 0