getMergedLocalBeanDefinition 合并BeanDefinition

950 阅读4分钟

在ApplicationContext的refresh方法中,finishBeanFactoryInitialization(beanFactory)这一步是初始化剩余的非懒加载的单例bean,之后会调用BeanFactory的preInstantiateSingletons()方法进行这些bean的加载工作。

在preInstantiateSingletons方法中,首先会从beanDefinitionNames集合中获取所有的beanName,之后会循环进行getBean。

但是在getBean之前,会有一个BeanDefinition的合并动作getMergedLocalBeanDefinition(beanName),对要get的bean的定义先进行合并。

合并的原因

在GenericBeanDefinition,ChildBeanDefinition中有一个parentName属性,表示该BeanDefinition的父BeanDefinition,如果该bean在定义中设置了parentName,那么在实例化之前会进行这两个BeanDefinition的合并。

一、例子

定义子类

@Data
public class ChildBean {
    private String name;
    private String age;
    private String address;
}

定义父类

@Data
public class FatherBean {
    private String name;
    private String age;
    private String address;
}
public class AnnotatedTestMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 将FatherBean注册到上下文的BeanFactory中
        RootBeanDefinition fatherBean = new RootBeanDefinition();
        fatherBean.setBeanClass(FatherBean.class);

        fatherBean.getPropertyValues().add("name", "父亲");
        fatherBean.getPropertyValues().add("age", "60");
        fatherBean.getPropertyValues().add("address", "北京");
        context.registerBeanDefinition("fatherBean", fatherBean);

        // 将ChildBean注册到上下文的BeanFactory中
        GenericBeanDefinition childBean = new GenericBeanDefinition();
        childBean.setBeanClass(ChildBean.class);
        childBean.getPropertyValues().add("name", "儿子");
        childBean.setParentName("fatherBean");
        context.registerBeanDefinition("childBean", childBean);
        context.refresh();
        System.out.println(context.getBean(ChildBean.class));
        System.out.println(context.getBean(FatherBean.class));
    }

ChildBean会继承FatherBean相同属性的值(age和address)

打印结果:

ChildBean(name=儿子, age=60, address=北京)
FatherBean(name=父亲, age=60, address=北京)
Process finished with exit code 0

二、AbstractBeanFactory中对于bean定义合并的代码逻辑

 //返回一个合并的 RootBeanDefinition,如果该bean定义是一个子bean定义,则遍历父bean定义
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
        //先从mergedBeanDefinitions容器中取
        //如果有,表示该bean定义已经合并过了,则就直接返回;如果没有,则进行合并
        RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
        if (mbd != null) {
                return mbd;
        }
        return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

/* 
 * 如果该bean定义是子bean定义,则通过与父级合并返回给定顶级 bean 的 RootBeanDefinition
 * @param beanName bean定义的名称
 * @param bd 原始的bean定义(Root/ChildBeanDefinition)
 * @return 给定bean的(可能合并的)RootBeanDefinition
 * @throws BeanDefinitionStoreException in case of an invalid bean definition
 */
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
                throws BeanDefinitionStoreException {
        return getMergedBeanDefinition(beanName, bd, null);
}

/**
 * 返回一个合并的RootBeanDefinition,如果该bean定义是一个子bean定义,则合并父bean定义
 * @param bean定义的名称
 * @param bd 原始的bean定义(Root/ChildBeanDefinition)
 * @param containingBd 如果是内部bean,则包含bean定义,如果是顶级 bean,则为null
 * @return 给定bean的(可能合并的)RootBeanDefinition
 * @throws BeanDefinitionStoreException in case of an invalid bean definition
 */
protected RootBeanDefinition getMergedBeanDefinition(
                String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
                throws BeanDefinitionStoreException {

        synchronized (this.mergedBeanDefinitions) {
                RootBeanDefinition mbd = null;
                if (containingBd == null) {
                        mbd = this.mergedBeanDefinitions.get(beanName);
                }

                if (mbd == null) {
                        //如果该bean定义没有parent,则不进行合并,返回包装后的RootBeanDefinition
                        if (bd.getParentName() == null) {
                                //如果该bean定义是RootBeanDefinition,则直接克隆一份BeanDefinition
                                if (bd instanceof RootBeanDefinition) {
                                        mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                                }
                                //如果不是RootBeanDefinition,则包装为RootBeanDefinition
                                else {
                                        mbd = new RootBeanDefinition(bd);
                                }
                        }
                        //如果该bean定义有parent
                        else {
                                // Child bean definition: needs to be merged with parent.
                                BeanDefinition pbd;
                                try {
                                        String parentBeanName = transformedBeanName(bd.getParentName());
                                        //如果parentName不是当前的beanName,则获取父bean合并后的bean定义
                                        if (!beanName.equals(parentBeanName)) {
                                                //递归调用进行父bean定义的合并
                                                pbd = getMergedBeanDefinition(parentBeanName);
                                        }
                                        else {
                                                BeanFactory parent = getParentBeanFactory();
                                                if (parent instanceof ConfigurableBeanFactory) {
                                                        pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                                                }
                                                else {
                                                        throw new NoSuchBeanDefinitionException(parentBeanName,
                                                                        "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                                                        "': cannot be resolved without an AbstractBeanFactory parent");
                                                }
                                        }
                                }
                                catch (NoSuchBeanDefinitionException ex) {
                                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                                        "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                                }
                                // Deep copy with overridden values.
                                mbd = new RootBeanDefinition(pbd);
                                //1.1 覆盖bean信息,用子bean定义中的属性,方法覆盖父bean定义中的属性,方法
                                mbd.overrideFrom(bd);
                        }

                        // Set default singleton scope, if not configured before.
                        if (!StringUtils.hasLength(mbd.getScope())) {
                                mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
                        }

                        // A bean contained in a non-singleton bean cannot be a singleton itself.
                        // Let's correct this on the fly here, since this might be the result of
                        // parent-child merging for the outer bean, in which case the original inner bean
                        // definition will not have inherited the merged outer bean's singleton status.
                        if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                                mbd.setScope(containingBd.getScope());
                        }

                        //将合并后的bean定义放入到缓存中
                        if (containingBd == null && isCacheBeanMetadata()) {
                                this.mergedBeanDefinitions.put(beanName, mbd);
                        }
                }
                return mbd;
        }
}

1.1覆盖Bean信息

AbstractBeanDefinition中对bean定义的覆盖

/**
 * Override settings in this bean definition (presumably a copied parent
 * from a parent-child inheritance relationship) from the given bean
 * definition (presumably the child).
 * <ul>
 * <li>Will override beanClass if specified in the given bean definition.
 * <li>Will always take {@code abstract}, {@code scope},
 * {@code lazyInit}, {@code autowireMode}, {@code dependencyCheck},
 * and {@code dependsOn} from the given bean definition.
 * <li>Will add {@code constructorArgumentValues}, {@code propertyValues},
 * {@code methodOverrides} from the given bean definition to existing ones.
 * <li>Will override {@code factoryBeanName}, {@code factoryMethodName},
 * {@code initMethodName}, and {@code destroyMethodName} if specified
 * in the given bean definition.
 * </ul>
 */
public void overrideFrom(BeanDefinition other) {
        //如有直接覆盖BeanClassName
        if (StringUtils.hasLength(other.getBeanClassName())) {
                setBeanClassName(other.getBeanClassName());
        }
        //如有作用域直接覆盖作用域
        if (StringUtils.hasLength(other.getScope())) {
                setScope(other.getScope());
        }
        //覆盖是否抽象
        setAbstract(other.isAbstract());
        //覆盖是否懒加载
        setLazyInit(other.isLazyInit());
        //覆盖工厂名
        if (StringUtils.hasLength(other.getFactoryBeanName())) {
                setFactoryBeanName(other.getFactoryBeanName());
        }
        //覆盖工厂方法名
        if (StringUtils.hasLength(other.getFactoryMethodName())) {
                setFactoryMethodName(other.getFactoryMethodName());
        }
        setRole(other.getRole());
        setSource(other.getSource());
        //拷贝属性
        copyAttributesFrom(other);

        if (other instanceof AbstractBeanDefinition) {
                AbstractBeanDefinition otherAbd = (AbstractBeanDefinition) other;
                if (otherAbd.hasBeanClass()) {
                        setBeanClass(otherAbd.getBeanClass());
                }
                if (otherAbd.hasConstructorArgumentValues()) {
                        getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
                }
                if (otherAbd.hasPropertyValues()) {
                        getPropertyValues().addPropertyValues(other.getPropertyValues());
                }
                if (otherAbd.hasMethodOverrides()) {
                        getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
                }
                setAutowireMode(otherAbd.getAutowireMode());
                setDependencyCheck(otherAbd.getDependencyCheck());
                setDependsOn(otherAbd.getDependsOn());
                setAutowireCandidate(otherAbd.isAutowireCandidate());
                setPrimary(otherAbd.isPrimary());
                copyQualifiersFrom(otherAbd);
                setInstanceSupplier(otherAbd.getInstanceSupplier());
                setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
                setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
                if (otherAbd.getInitMethodName() != null) {
                        setInitMethodName(otherAbd.getInitMethodName());
                        setEnforceInitMethod(otherAbd.isEnforceInitMethod());
                }
                if (otherAbd.getDestroyMethodName() != null) {
                        setDestroyMethodName(otherAbd.getDestroyMethodName());
                        setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod());
                }
                setSynthetic(otherAbd.isSynthetic());
                setResource(otherAbd.getResource());
        }
        else {
                getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
                getPropertyValues().addPropertyValues(other.getPropertyValues());
                setResourceDescription(other.getResourceDescription());
        }
}


protected void copyAttributesFrom(AttributeAccessor source) {
        Assert.notNull(source, "Source must not be null");
        String[] attributeNames = source.attributeNames();
        for (String attributeName : attributeNames) {
                setAttribute(attributeName, source.getAttribute(attributeName));
        }
}