《Spring源码深度解析》三(1)

2019 Java 开发者跳槽指南.pdf (吐血整理)….>>>
3.1:bean标签的解析及注册

3.1.1:第一步,进入processBeanDefinition(ele, delegate),即默认标签解析函数:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //1.首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后,bdHolder实例已经包含我们配置文件中配置的各种属性了,例如class、name、id、alias之类的属性。
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        //2.当返回的bdHolder不为空的情况下若存在默认标签的子节点下还有自定义属性,还需要再次对自定义标签进行解析。
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            //3.解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法。
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        //4.发出响应事件,通知相关的监昕器,这个bean 已经加载完成了。
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

时序图:

《Spring源码深度解析》三(1)

3.1.2:第二步,逐步解析上述四个过程的代码

3.1.2.1:第一个过程:元素解析及信息提取

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);分为四步:

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    //1.解析id属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    //解析name属性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    //分割name属性
    List<String> aliases = new ArrayList<>();
    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.isTraceEnabled()) {
            logger.trace("No XML 'id' specified - using '" + beanName +
                    "' as bean name and " + aliases + " as aliases");
        }
    }

    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    //2.进一步解析其他所有属性并统一封装至GenericBeanDefinition 类型的实例中
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                //3.如果不存在beanName
                //那么根据Spring中提供的命名规则为当前bean生成对应的beanName
                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);
        //4.将获取到的信息封装到BeanDefinit i onHo ld er 的实例中。
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}

3.1.2.2:继续看看步骤2中对标签其他属性的解析过程

在这个方法中,bean标签的所有其他属性都会出现

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

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

    String className = null;
    //解析class属性
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    String parent = null;
    //解析parent属性
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }

    try {
        //1.创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        //2.硬编码解析默认bean的各种属性
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        //提取Description
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        //3.解析元数据
        parseMetaElements(ele, bd);
        //4.解析lookup-method属性
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        //5.解析replaced-method属性
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        //6.解析构造方法参数
        parseConstructorArgElements(ele, bd);
        //7.解析property子元素
        parsePropertyElements(ele, bd);
        //8.解析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;
}

3.1.2.3:接下来,分析bean标签其中的复杂属性,即上述代码

3.1.2.3.1:首先,创建用于属性承载的BeanDefinition,即上述代码的注释1

BeanDefinition是一个接口,是配置文件元素标签在容器中的内部表示形式,标签的属性如class、scope、lazy-init分别对应着beanClass、scope、lazyInit字段

BeanDefinition有三个实现类:RootBeanDefinition 、ChildBeanDefinition、GenericBeanDefinition。
三种实现都继承了AbstractBeanDefiniton

RootBeanDefinition是最常用的实现类,对应一般性的元素标签
ChildBeanDefinition存在于父子bean,父bean用RootBeanDefinition表示,子bean用ChildBeanDefinition表示;若无父子bean,则bean用RootBeanDefinition表示
GenericBeanDefinition是bean文件配置属性定义类,是一站式服务类

类图如下:

《Spring源码深度解析》三(1)

如何使用这些BeanDefiniton呢,即配置信息?
Spring通过BeanDefinition将配置文件中的配置信息转换为容器的内部表示,并将这些BeanDefiniton 注册到BeanDefinitonRegistry中。
Spring容器的BeanDefinitionRegistrγ就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从BeanDefinitionRegistry中读取配置信息

知道上面这些类后,就可以创建用于承载属性的实例了,即创建GenericBeanDefinition类实例:

《Spring源码深度解析》三(1)


3.1.2.3.2:创建了bean信息的承载实例后,就可以解析各种属性了,即注释2

首先进入parseBeanDefinitionAttributes方法,对element所有元素属性进行解析,到这里就完成了对bean标签所有属性的解析:

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
        @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd)
 
{
    //scope或singleton,若没有指定,则设置默认的值
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }
    else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    }
    else if (containingBean != null) {
        bd.setScope(containingBean.getScope());
    }
    //解析abstract属性
    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }
    //lazy-init
    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (isDefaultValue(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    //若没有设置或设置成其他字符,则设置为false
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    //autowired
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));
    //depends-on
    if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
        String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
        bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
    }
    //autowire-candidate
    String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    if (isDefaultValue(autowireCandidate)) {
        String candidatePattern = this.defaults.getAutowireCandidates();
        if (candidatePattern != null) {
            String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
            bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
        }
    }
    else {
        bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    }
    //primary
    if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
        bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
    }
    //init-method
    if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
        String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
        bd.setInitMethodName(initMethodName);
    }
    else if (this.defaults.getInitMethod() != null) {
        bd.setInitMethodName(this.defaults.getInitMethod());
        bd.setEnforceInitMethod(false);
    }
    //destroy-method
    if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
        String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
        bd.setDestroyMethodName(destroyMethodName);
    }
    else if (this.defaults.getDestroyMethod() != null) {
        bd.setDestroyMethodName(this.defaults.getDestroyMethod());
        bd.setEnforceDestroyMethod(false);
    }
    //factory-mathod
    if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
        bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
    }
    //factory-bean
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }
    return bd;
}
3.1.2.3.3:解析子元素meta,即注释3
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
    //获得当前节点的所有子元素
    NodeList nl = ele.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        //提取meta
        if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
            Element metaElement = (Element) node;
            String key = metaElement.getAttribute(KEY_ATTRIBUTE);
            String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
            //使用key、value构造BeanMetadataAttribute
            BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
            attribute.setSource(extractSource(metaElement));
            //记录信息
            attributeAccessor.addMetadataAttribute(attribute);
        }
    }
}
3.1.2.3.4:解析子元素lookup-method(获取器注入),即注释4
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        //仅当在Spring默认bean的子元素下且为<lookup-method>时有效
        if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
            Element ele = (Element) node;
            //获取要修饰的方法
            String methodName = ele.getAttribute(NAME_ATTRIBUTE);
            //获取配置返回的bean
            String beanRef = ele.getAttribute(BEAN_ELEMENT);
            //使用LookupOverride来进行数据承载
            // 并记录载AbstractBeanDefinition中的methodOverrides属性中
            LookupOverride override = new LookupOverride(methodName, beanRef);
            override.setSource(extractSource(ele));
            overrides.addOverride(override);
        }
    }
}
3.1.2.3.5:解析子元素replaced-method,即注释5
/**
 * 跟look-up一样,构造了一个MethodOverride
 * 并记录载AbstractBeanDefinition中的methodOverrides属性中
 * @param beanEle
 * @param overrides
 */

3.1.2.3.6:解析子元素constructor-arg,即注释6

流程总结:
1.解析每个constructor-arg
2.封装constructor-arg的type、name、index(额外判断)和属性元素(3)
3.属性元素:解析constructor-arg的ref、value或子元素(4)
4.子元素:idref、map、list等

3.1.2.3.7:解析子元素property,即注释7
1554723964301
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            //解析每个property
            parsePropertyElement((Element) node, bd);
        }
    }
}
//与构造函数注入方式不同的是将返回值使用PropertyValue封装,并记录在了BD的PropertyValues属性中
//构造函数则是BeanDefinition的constructorArgumentValues
public void parsePropertyElement(Element ele, BeanDefinition bd) {
    //获得配置中name的值
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        //不允许多次对同一属性配置
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        Object val = parsePropertyValue(ele, bd, propertyName);
        //使用PropertyValue封装
        PropertyValue pv = new PropertyValue(propertyName, val);
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        //记录
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
        this.parseState.pop();
    }
}
3.1.2.3.8:解析子元素qualifier,即注释8
类似3.1.2.3.7

此时,就完成了第一个过程,即BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);的解析,完成了对XML文档到GenericBeanDefinition的转换,即XML中所有的配置都可以在GenericBeanDefinition的实例中找到

GenericBeanDefinition只是子类,大部分通用属性保存在AbstractBeanDefinition中
如:scope、singleton、prototype、abstractFlag、lazyInit、autowireMode、dependsOn等
技巧:值得注意的是primary、dependsOn的作用,实现了单接口多实现类和多重依赖实例化:

《Spring源码深度解析》三(1)

3.1.2.2:第二个过程:解析默认标签中的自定义标签元素

(注:bean的默认类型和自定义类型的解析都是以bean形式出现,而默认标签的自定义标签是在默认标签的里面,作为属性出现的)

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

流程:首先获取属性或者元素的命名空间, 以此来判断该元素或者属性是否适用于自定义标签的解析条件, 找出自定义类型所对应的NamespaceHandler 并进行进一步解析。

3.1.2.3:第三个过程:注册

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

        throws BeanDefinitionStoreException 
{

    //1.使用beanName做唯一标识注册,通过beanName注册BeanDefinition
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    //2.注册所有的别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}
//注释1.流程:
1. 对AbstractBeanDefinition的校验。在解析XML文件的时候我们提过校验,但是此校验非彼校验,之前的校验时针对于XML格式的校验,而此时的校验时针是对于AbstractBeanDefinition的methodOverrides属性的。
2. 对beanName已经注册的情况的处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖。
3. 加入map 缓存。
4. 清除解析之前留下的对应beanNam巳的缓存。
//注释2.流程
1. alias与beanName相同情况处理。若alias与beanName名称相同则不需要处理并删除掉原有alias
2. alias覆盖处理。若aliasName已经使用井已经指向了另一beanName则需要用户的设置进行处理。
3. alias 循环检查。当A->B存在时,若再次出现A->C->B则抛出异常
4. 注册alias 。

3.1.2.4 通知监听器解析并注册完成

此为扩展,Spring暂无处理


原文始发于微信公众号(不止于Java):《Spring源码深度解析》三(1)