Spring源码学习 | 3 Spring配置解析与BeanDefinition加载

301 阅读9分钟

前言

前面我们梳理了Spring容器初始话的整体流程,今天来单独讲一讲初始化过过程重点之一,Spring配置的解析和BeanDefinition的加载。

虽然Spring的配置有很多形式,不再限于xml文件。但是本文还是以前文的spring-demo项目为例,分析xml形式配置的配置文件spring-beans.xml是如何解析的。掌握xml配置形式之后,再看其他方式,其实就触类旁通了。

原demo扩充

之前demo里内容比较少,我们先丰富一下,然后再分析。项目地址: spring-xml-demo-enhanced

项目结构结构

image.png

编码

Component、Component空类

package cn.dingyufan.learnspring.springxmldemoenhanced.component;

import org.springframework.stereotype.Component;

@Component
public class OneComponent {
}

package cn.dingyufan.learnspring.springxmldemoenhanced.component;

import org.springframework.stereotype.Component;

@Component
public class TwoComponent {
}

HelloController增加了oneComponent注入

package cn.dingyufan.learnspring.springxmldemoenhanced.controller;

import cn.dingyufan.learnspring.springxmldemoenhanced.component.OneComponent;
import cn.dingyufan.learnspring.springxmldemoenhanced.service.HelloService;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Autowired
    private HelloService helloService;

    @Autowired
    private OneComponent oneComponent;

    // 属性注入之后就可以自动打印,方便验证
    @PostConstruct
    private void init() {
        System.out.println("HelloController.init(),helloService=>" + helloService);
        System.out.println("HelloController.init(),oneComponent=>" + oneComponent);
    }

    @GetMapping("/hello")
    public ResponseEntity<String> hello(HttpServletRequest request) {
        return ResponseEntity.ok("Hello Spring!");
    }

    @GetMapping("/check")
    public ResponseEntity<String> check(HttpServletRequest request) {
        return ResponseEntity.ok(String.valueOf(helloService.hashCode()));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("HelloController注入applicationContext =>" + applicationContext.getDisplayName());
        this.applicationContext = applicationContext;
    }
}


HelloService无变化

package cn.dingyufan.learnspring.springxmldemoenhanced.service;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;


public class HelloService implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("HelloService注入applicationContext =>" + applicationContext.getDisplayName());
        this.applicationContext = applicationContext;
    }
}

WorldService注入了多种内容,一个对象,一个数字,一个数组。都是通过xml配置配置,然后setter方法注入的。init()方法说明一下,这里是在xml配置的init-method项,调用顺序是在bean属性注入之后的,所以我们借助这个方法来检查内容是否注入。

package cn.dingyufan.learnspring.springxmldemoenhanced.service;

import java.util.List;

public class WorldService {
    private HelloService helloService;
    private Integer year;
    private List<String> ultraman;

    // 在xml配置了<bean>的init-method属性
    private void init() {
        System.out.println("WorldService.init(),helloService=>" + helloService);
        System.out.println("WorldService.init(),year=>" + year);
        System.out.println("WorldService.init(),ultraman=>" + ultraman);
    }

    public void setHelloService(HelloService helloService) {
        this.helloService = helloService;
    }

    public void setUltraman(List<String> ultraman) {
        this.ultraman = ultraman;
    }

    public void setYear(Integer year) {
        this.year = year;
    }
}

配置

配置上面,在demo里使用了常见的一些配置标签。

首先可以看到新增了一个spring-component.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--扫描注册base-package下的组件-->
    <context:component-scan base-package="cn.dingyufan.learnspring.springxmldemoenhanced.component"/>

</beans>

spring-beans.xml文件增加了worldService定义,同时为worldService配置了属性;增加了<import>标签,这个作用相当于把spring-component.xml的内容都引入spring-beans.xml。<import>标签可以让我们更加方便的拆分管理bean,避免一个配置文件巨大。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloService" class="cn.dingyufan.learnspring.springxmldemoenhanced.service.HelloService"/>

    <bean id="worldService" class="cn.dingyufan.learnspring.springxmldemoenhanced.service.WorldService" init-method="init">
        <property name="helloService" ref="helloService"/>
        <property name="year" value="2021"/>
        <property name="ultraman">
            <list>
                <value>泰罗</value>
                <value>赛文</value>
                <value>艾斯</value>
            </list>
        </property>
    </bean>

    <import resource="spring-component.xml"/>
</beans>

spring-mvc.xml、web.xml、pom.xml都没有变化,不再赘述,需要的话可以从前文获取

运行

从控制台打印的信息可以看到,HelloService中的对象、数字、数组都成功注入;HelloController新添加的oneComponent也已经成功注入。说明我们的配置都已经生效了。

image.png

源码解析

从上文可知,配置文件的加载是在beanFactory的刷新过程中的。我们仍然以XmlWebApplicationContext为例,从obtainFreshBeanFactory()方法看起。

AbstractApplicationContext

XmlWebApplicationContext的obtainFreshBeanFactory()方法是其父类AbstractApplicationContext实现

    // AbstractApplicationContext.java
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 空方法
        refreshBeanFactory();
        return getBeanFactory();
    }

AbstractRefreshableApplicationContext

而XmlWebApplicationContext的refreshBeanFactory()方法是父类AbstractRefreshableApplicationContext实现。

    // AbstractRefreshableApplicationContext.java
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            // 空方法,作用是解析配置加载BeanDefinition
            loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

XmlWebApplicationContext

到这里这个loadBeanDefinitions(beanFactory)方法终于是XmlWebApplicationContext自己实现了。

    // XmlWebApplicationContext.java
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 为BeanFactory创建一个XmlBeanDefinitionReader
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // 为XmlBeanDefinitionReader添加配置
        beanDefinitionReader.setEnvironment(getEnvironment());
        // 把XmlWebApplicationContext自己设为ResourceLoader
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // 空方法,给子类添加它想要的配置的。又是模板方法模式。
        initBeanDefinitionReader(beanDefinitionReader);
        // 加载BeanDefinition
        loadBeanDefinitions(beanDefinitionReader);
    }

我们看到,上面为解析配置准备了一个XmlBeanDefinitionReader,给子类留了自定义配置的口子,然后真正的在另一个入参不同的loadBeanDefinitions(reader)方法。

    // XmlWebApplicationContext.java
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            for (String configLocation : configLocations) {
                reader.loadBeanDefinitions(configLocation);
            }
        }
    }

从代码中可以看到,loadBeanDefinitions(reader)方法就是遍历我们的xml配置文件路径,然后依次交给XmlBeanDefinitionReader去处理。

插一句,这个configLocations还记得是哪里来的吗?它是我们在web.xml中配置的context-param,然后在ContextLoader中,从servletContext获取并赋值给applicationContext的。

AbstractBeanDefinitionReader

我们来看XmlBeanDefinitionReader拿到配置文件路径之后,做了什么处理

  • 获取ResourceLoader
  • 使用ResourceLoader将配置文件加载为Resource
  • 遍历加载到的Resource,调用子类方法加载BeanDefinition
    // AbstractBeanDefinitionReader.java。是XmlBeanDefinitionReader父类
    @Override
    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(location, null);
    }
    
    
    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        // 这个ResourceLoader就是在前面XmlWebApplicationContext类的loadBeanDefinitions(beanFactory)方法设置的
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }
        
        // XmlWebApplicationContext是实现了ResourcePatternResolver接口的
        if (resourceLoader instanceof ResourcePatternResolver) {
            try {
                // 使用ResourceLoader将配置文件加载为Resource
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int count = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    Collections.addAll(actualResources, resources);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                }
                return count;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            Resource resource = resourceLoader.getResource(location);
            int count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
            }
            return count;
        }
    }


    @Override
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        for (Resource resource : resources) {
            // 这里这个loadBeanDefinitions(resource)是子类自己实现
            // 对应我们这就是XmlWebApplicationContext中的loadBeanDefinitions(resource)方法
            count += loadBeanDefinitions(resource);
        }
        return count;
    }

首先可以看到,它通过getResourceLoader()方法拿到一个ResourceLoader,这个ResourceLoader正是前面XmlWebApplicationContext类的loadBeanDefinitions(beanFactory)方法里,我们给他设置的,设置的值为XmlWebApplicationContext对象本身。可以往上翻一点看看。

然后判断是否是ResourcePatternResolver实现类。我们知道XmlWebApplicationContext是实现了ApplicationContext的,而ApplicationContext接口则是直接继承了ResourcePatternResolver接口的的。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

	@Nullable
	String getId();

	String getApplicationName();

	String getDisplayName();

	long getStartupDate();

	@Nullable
	ApplicationContext getParent();

	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}

我们搜索ResourcePatternResolver的实现类也可以清楚的看到有XmlWebApplicationContext。

image.png

然后将配置文件加载为Resource。这个加载是依赖于XmlWebApplicationContext的父类AbstractApplicationContext提供的ResourcePatternResolver类型的成员变量resourcePatternResolver。AbstractApplicationContext的构造方法里,会创建变量实例,是一个PathMatchingResourcePatternResolver。具体过程就先不说了,先知道是哪个类来做这个事。

    // AbstractApplicationContext.java
    public AbstractApplicationContext() {
        this.resourcePatternResolver = getResourcePatternResolver();
    }
    
    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }

XmlBeanDefinitionReader

最后AbstractBeanDefinitionReader调用子类XmlBeanDefinitionReader方法解析Resource。又回到XmlWebApplicationContext类,会将Resource包装成EncodedResource;然后以IO流读取文件,将XML文件转换成对应的Document对象,方便程序处理。然后实例化一个BeanDefinitionDocumentReader来读取Document对象。

    // XmlBeanDefinitionReader.java
    @Override
    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.isTraceEnabled()) {
            logger.trace("Loading XML bean definitions from " + encodedResource);
        }
        
        // 目前已加载的Resource
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }

        try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            // inputStream读取Resource,并继续
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }
    
    
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            // 解析xml,形成对应的Document对象
            Document doc = doLoadDocument(inputSource, resource);
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        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);
        }
    }
    
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

DefaultBeanDefinitionDocumentReader

读取Document对象默认的是使用DefaultBeanDefinitionDocumentReader,在方法中又创建了BeanDefinitionParserDelegate代理类。方法这里涉及到了namespace、profile的处理,目前先不细说;两个空方法也没啥可讨论的;主要关注于parseBeanDefinitions(root, this.delegate)。

    // DefaultBeanDefinitionDocumentReader.java
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            doRegisterBeanDefinitions(doc.getDocumentElement());
    }

    protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            // 判断是否配置了profile。
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
    }

在下面这个方法里,分两种情况处理,一种是默认namespace的,另一种其实就是自定义的namespace(自定义标签)。自定义标签的应用在Spring应用也非常广泛,比如我们熟知的SpringMVC、Dubbo等框架都有自定义标签的使用。在这我们只看默认namespace的处理,另一种以后单独讲。

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

对于默认namespace的Node,最后都会来进入parseDefaultElement(ele, delegate)方法。这个方法里的四个if分别解析不同的标签。标签解析大同小异,我们以<bean>的解析为例子。

    // DefaultBeanDefinitionDocumentReader.java
    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        // <import>
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        // <alias>
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        // <bean>
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        // <beans>
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

进入processBeanDefinition(ele, delegate)方法我们可以看到,下面的方法做了四件事

  • 借助解析delegate代理对象解析节点为BeanDefinitionHolder
  • 如果定义了装饰器Decorator,会对BeanDefinition进行装饰
  • 注册最终的BeanDefinition
  • 发送bean注册事件

其实第一步我们是最关心的,我们一会再看负责解析的代理对象是如何处理的。这里提到使用装饰器Decorator,这个是做什么呢,简单说一下。这里其实就是根据节点的namespaceUri寻找对应的NamespaceHandler,然后看NamespaceHandler中是不是注册了处理此节点名称的装饰器Decorator,若有就应用装饰器进行装饰。以后会细说。

    // DefaultBeanDefinitionDocumentReader.java
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 解析节点,创建BeanDefinitionHolder
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            // 如果定义了装饰器,会对BeanDefinition进行装饰。
            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);
            }
            // 发送bean注册事件
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

BeanDefinitionParserDelegate

我们还是关注BeanDefinitionHolder是怎么来的。delegate解析的主要逻辑如下

  • 读取node上的id, name
  • 取beanName并检查是否唯一
  • 解析得AbstractBeanDefinition
    • 根据className, parent类型,以及ClassLoader创建一个AbstractBeanDefinition
    • 读取各种属性,填充到AbstractBeanDefinition
  • 再次尝试取beanName
  • 组装成BeanDefinitionHolder
    // BeanDefinitionParserDelegate.java
    @Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
            return parseBeanDefinitionElement(ele, null);
    }
    
    @Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        // 读取node上的id, name
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List<String> aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
        
        // beanName默认是id, 如果id没配name配了,就取第一个name做id
        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = aliases.remove(0);
            if (logger.isTraceEnabled()) {
                logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }
        
        if (containingBean == null) {
            // 检查beanName是否重复,重复则抛出异常
            checkNameUniqueness(beanName, aliases, ele);
        }
        
        // 解析节点到AbstractBeanDefinition
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                // = =这一大段就是,如果没有beanName就生成一个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 (logger.isTraceEnabled()) {
                        logger.trace("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            // AbstractBeanDefinition、beanName, aliases组装成BeanDefinitionHolder
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }
    
    
    @Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));
        
        // 读取node中的class属性
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        // 读取node中的parent属性
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
            // 根据className, parent类型,以及ClassLoader创建一个AbstractBeanDefinition
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 读取各种属性,填充到AbstractBeanDefinition。如:
            // singleton、scope、abstract、lazy-init、autowire、depends-on、autowire-candidate、
            // primary、init-method、destroy-method、factory-method、factory-bean
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            // 解析descriptionb标签
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            
            // 解析meta标签
            parseMetaElements(ele, bd);
            // 解析lookup-method标签
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            // 解析replaced-method标签
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

            // 解析constructor-arg标签
            parseConstructorArgElements(ele, bd);
            // 解析property标签
            parsePropertyElements(ele, bd);
            // 解析qualifier标签
            parseQualifierElements(ele, bd);

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

            return bd;
        }
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }

结语

洋洋洒洒写了一大段,可能用一张图来表示一下流程可能会更清晰一些。

xml配置文件_bean_标签解析.jpg