4.BeanDefinition的实现类详解

339 阅读20分钟

BeanDefinition的实现类。包括AbstractBeanDefinition、RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition、AnnotateGenericBeanDefinition、ScannerGenericBeanDefinition。

1.AbstractBeanDefinition

AbstractBeanDefinition是抽象类,它是众多BeanDefinition子类的父类。

前两篇文章讲的BeanDefinition属性值大都保存在AbstractBeanDefinition,并实现了子BeanDefinition通用方法。同时它也继承了BeanMetadataAttributeAccessor完成attribute和source的操作。

我们看一下它的关键源码,重点属性使用★标记出来了:

//AbstractBeanDefinition extends BeanMetadataAttributeAccessor ★
//AbstractBeanDefinition继承了BeanMetadataAttributeAccessor
//BeanMetadataAttributeAccessor是BeanDefinition的实现类
//那么借用上一批文章中的总结:BeanDefinition的实现类BeanMetadataAttributeAccessor实现
//BeanMetadataElement继承了AttributeAccessorSupport。既可以设置和获取源,也可以设置和获取bd的属性值。
//所以AbstractBeanDefinition既可以设置和获取源,也可以设置和获取bd的属性值。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
        implements BeanDefinition, Cloneable {

    // 此处省略静态变量以及final变量
    
    /**
     * bean的对应的class ★
     */
    @Nullable
    private volatile Object beanClass;
    
    /**
     * bean的作用范围,对应bean属性scope即单例、多例 ★
     */
    @Nullable
    private String scope = SCOPE_DEFAULT;
    
    /**
     * 是否是抽象,对应bean属性abstract ★
     */
    private boolean abstractFlag = false;
    
    /**
     * 是否延迟加载,对应bean属性lazy-init ★
     */
    private boolean lazyInit = false;
    
    /**
     * 自动注入模式,对应bean属性autowire ★
     */
    private int autowireMode = AUTOWIRE_NO;
    
    /**
     * 依赖检查,Spring 3.0后弃用这个属性
     */
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;
    
    /**
     * 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on★
     */
    @Nullable
    private String[] dependsOn;
    
    /**
     * autowireCandidate ★
     * autowireCandidate属性设置为false时容器在查找自动装配对象时,
     * 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
     * 但是该bean本身还是可以使用自动装配来注入其他bean
     */
    private boolean autowireCandidate = true;
    
    /**
     * 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary ★
     */
    private boolean primary = false;
    
    /**
     * 用于记录Qualifier,对应子元素qualifier ★
     */
    private final Map<String, AutowireCandidateQualifier> qualifiers= new LinkedHashMap<>(0);

    @Nullable
    private Supplier<?> instanceSupplier;
    /**
     * 允许访问非公开的构造器和方法,程序设置
     */
    private boolean nonPublicAccessAllowed = true;
    
    /**
     * 是否以一种宽松的模式解析构造函数,默认为true,
     * 如果为false,则在以下情况
     * interface ITest{}
     * class ITestImpl implements ITest{};
     * class Main {
     *     Main(ITest i) {}
     *     Main(ITestImpl i) {}
     * }
     * 抛出异常,因为Spring无法准确定位哪个构造函数程序设置
     */
    private boolean lenientConstructorResolution = true;
    
    /**
     * factoryBeanName ★
     * 对应bean属性factory-bean,用法:
     * <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
     * <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
     *意思是通过InstanceFactoryBean的方法createTime创建currentTime
     */
    @Nullable
    private String factoryBeanName;
    
    /**
     * 对应bean属性factory-method ★
     */
    @Nullable
    private String factoryMethodName;
    
    /**
     * 记录构造函数注入属性,对应bean属性constructor-arg
     */
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;
    
    /**
     * 普通属性集合,就是存放你业务类的属性的地方★
     */
    @Nullable
    private MutablePropertyValues propertyValues;
    
    /**
     * 方法重写的持有者,记录lookup-method、replaced-method元素★
     * 目前很少用了
     */
    @Nullable
    private MethodOverrides methodOverrides;
    
    /**
     * 初始化方法,对应bean属性init-method ★
     */
    @Nullable
    private String initMethodName;
    
    /**
     * 销毁方法,对应bean属性destroy-method ★
     */
    @Nullable
    private String destroyMethodName;
    
    /**
     * 是否执行init-method,程序设置
     */
    private boolean enforceInitMethod = true;
    
    /**
     * 是否执行destroy-method,程序设置
     */
    private boolean enforceDestroyMethod = true;
    
    /**
     * 是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设置
     * synthetic意思是合成的
     */
    private boolean synthetic = false;
    
    /**
     * 定义这个bean的应用范围 ★
     * APPLICATION:用户
     * INFRASTRUCTURE:完全内部使用,与用户无关
     * SUPPORT:某些复杂配置的一部分,程序设置
     */
    private int role = BeanDefinition.ROLE_APPLICATION;
    
    /**
     * bean的描述信息
     */
    @Nullable
    private String description;
    
    /**
     * 这个bean定义的资源
     */
    @Nullable
    private Resource resource;
}

操作方法我就不列出来了,主要就是对属性的设置和获取,类似于getter和setter方法,读者自行阅读。

这些属性很重要,建议多读几遍加深印象!

这些属性很重要,建议多读几遍加深印象!

这些属性很重要,建议多读几遍加深印象!

总之,AbstractBeanDefinition 就是保存了属性值并对属性值进行设置和读取。记住这一点就行了

AbstractBeanDefinition 其实已经涵盖了所有属性了,spring为什么要提供这么多的子类?

正所谓,既生瑜何生亮!

笔者认为,完全可以用一个AbstractBeanDefinition 代替所有的子类,只不过spring为了模块化,不同的BeanDefinition可能从代码角度来讲都一样,但是从设计角度来讲我们要模块化,要拆分。

不同模块的BeanDefinition无论从设计还是功能肯定有差异,我们当然可以将这些差异规避在AbstractBeanDefinition ,但是这不利于维护和扩展,更不利于阅读理解。

打个比方,最近在做通用告警模板,告警的方式有3种钉钉、企微、飞书。

每个告警方式都提供了不同的api供我们调用,每个api的入参的参数类型、参数名称都不相同。

比如钉钉用的是msgType、飞书用的是msg_type、企微用的是messageType

当然,我们可以提供1个WarnPushDTO,把钉钉、企微、飞书的参数都放进去。

    @Data
    public class WarnPushDTO{
        private String msgType;
        private String msg_type;
        private String messageType;
    }

然后提供1个统一的告警方法。

public static void warnPush(WarnPushDTO dto)

看起来完美!但是对于用的人来说可能就很不友好了,我要用企微,该设置哪个参数呢?

对于用的人来说,我只知道我需要调用企微的告警,你不需要给我搞那些有的没的!

针对这个问题怎么解决呢?上代码:

    @Data
    public class WarnPushDTO{
    }
     @Data
    public class weChatWarnPushDTO extends WarnPushDTO{
        private String messageType;
    }

在调用warnPush方法的时候传入 new weChatWarnPushDTO().setMessageType("text");

哎,这就是迪米特法则嘛也就是最小知识法则! 我不需要知道的我不用知道!

对于BeanDefinition也是如此,某些BeanDefinition只用于某些固定的场景,只需要操作某些固定的属性即可。所以对于某些我不需要特意去操作的属性,我也没必要知道你的存在。我只操作我要操作的属性即可。相当于把细节和通用的属性都放在了父类中。

为什么AbstractBeanDefinition没有像上面一样把所有的属性都放在子类中呢?

个人理解是某些BeanDefinition只用于某些固定的场景,只需要操作某些固定的属性即可,但是有一些通用的属性还是需要的,所以把这些通用的属性全都放在了AbstractBeanDefinition中,如果真的需要操作那么直接调用super的方法即可。

AbstractBeanDefinition的MutablePropertyValues

这里讲一下这行代码。这行代码设置的是对象的属性值。

//设置beanDefinition的属性值
beanDefinition.setAttribute("name","源码之路");
//设置对象的属性值
beanDefinition.getPropertyValues().addPropertyValue("name","彭方亮");

上文AbstractBeanDefinition 源码中有一个MutablePropertyValues类型的属性叫propertyValues

/**
 * 普通属性集合,就是存放你业务类的属性的地方
 */
@Nullable
private MutablePropertyValues propertyValues;

什么意思呢?propertyValues只能保存你业务类的属性,比如业务类InterService中有个name属性.

root.getPropertyValues().add("name","源码之路");

在后期spring实例化过程中,会将propertyValues中的属性值一一对应的赋值给业务对象。

等同于xml文件中的配置:

     <bean  id="index" class="com.InterService" >
           <property name="name" value="源码之路"></property>
     </bean>

如果,我设置了一个在InterService类中不存在的属性,就会报错,比如设置1个age属性。

image.png

image.png

我说过,AbstractBeanDefinition中的属性以后都会讲到,别急,这个propertyValues知道啥意思了吧?

propertyValues区别于attribute:

attributribute是beanDefinition的属性比如懒加载、单例等。

propertyValues是对象的属性比如年龄、身高等。

//设置属性值
beanDefinition.setAttribute("AttributeAccessor","源码之路");
//将beanDefinition注册到spring容器中
context.registerBeanDefinition("interService",beanDefinition);
//加载或者刷新当前的配置信息
context.refresh();
//拿到属性信息
String[] attributes = context.getBeanDefinition("interService").attributeNames();

2.ChildBeanDefinition:必须设置parentName

我们看一下ChildBeanDefinition源码中的类注解:

 * <p><b>NOTE:</b> Since Spring 2.5, the preferred way to register bean
 * definitions programmatically is the {@link GenericBeanDefinition} class,
 * which allows to dynamically define parent dependencies through the
 * {@link GenericBeanDefinition#setParentName} method. This effectively
 * supersedes the ChildBeanDefinition class for most use cases.

翻译一下

spring2.5以后GenericBeanDefinition是首选的,也就是说spring2.5以前的版本根本就没有GenericBeanDefinition这个类。
Spring总得向前发展啊,更重要的是尽可能的保持向下兼容呀!
其实,RootBeanDefinition也有这种类似的注解,你不信你去看源码!
现如今,我们已经不使用ChildBeanDefinition了,完全被GenericBeanDefinition给替代了,但是还在使用RootBeanDefinition。

ChildBeanDefinition不能独立存在,他必须继承一个父类,为什么?我们看源码:

    public class ChildBeanDefinition extends AbstractBeanDefinition {

        //父类名称
        @Nullable
        private String parentName;

        /**
         * 构造函数,必须设置一个父类
         */
        
        public ChildBeanDefinition(String parentName) {
            super();
            this.parentName = parentName;
        }

        /**
         * 构造函数,设置父类和业务类属性   
         */
        public ChildBeanDefinition(String parentName, MutablePropertyValues pvs) {
            super(null, pvs);
            this.parentName = parentName;
        }

        /**
         * 构造函数,设置父类,业务类构造函数的参数,业务类属性   
         */
        public ChildBeanDefinition(String parentName,
                                   ConstructorArgumentValues cargs, 		
                                   MutablePropertyValues pvs) {
            super(cargs, pvs);
            this.parentName = parentName;
        }

        /**
         * 构造函数,设置父类,业务类beanClass,业务类构造函数的参数,业务类属性      
         */
        public ChildBeanDefinition( String parentName,
                                   	Class<?> beanClass,
                                   	ConstructorArgumentValues cargs, 
                                   	MutablePropertyValues pvs) {

            super(cargs, pvs);
            this.parentName = parentName;
            setBeanClass(beanClass);
        }

        /**
         * 构造函数,设置父类,业务类名称,业务类构造函数的参数,业务类属性   
         */
        public ChildBeanDefinition(String parentName, 
            					   String beanClassName,
            						ConstructorArgumentValues cargs,
           	 						MutablePropertyValues pvs) {
            super(cargs, pvs);
            this.parentName = parentName;
            setBeanClassName(beanClassName);
        }

        /**
         * 构造函数,从另一个ChildBeanDefinition进行属性copy   
         */
        public ChildBeanDefinition(ChildBeanDefinition original) {
            super(original);
        }


        //设置父类名称
        @Override
        public void setParentName(@Nullable String parentName) {
            this.parentName = parentName;
        }

        //获取父类名称
        @Override
        @Nullable
        public String getParentName() {
            return this.parentName;
        }

        //校验,会发现,如果没有父类就会报错
        @Override
        public void validate() throws BeanDefinitionValidationException {
            super.validate();
            if (this.parentName == null) {
                throw new BeanDefinitionValidationException
                    			("'parentName' must be set in ChildBeanDefinition");
            }
        }


        //生成一个新的ChildBeanDefinition,并进行属性值复制
        @Override
        public AbstractBeanDefinition cloneBeanDefinition() {
            return new ChildBeanDefinition(this);
        }

        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (!(other instanceof ChildBeanDefinition)) {
                return false;
            }
            ChildBeanDefinition that = (ChildBeanDefinition) other;
            return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) 
                    												&& super.equals(other));
        }

        @Override
        public int hashCode() {
            return ObjectUtils.nullSafeHashCode(this.parentName) * 29 + super.hashCode();
        }

        @Override
        public String toString() {
            return "Child bean with parent '" + this.parentName + "': " + super.toString();
        }

    }

ChildBeanDefinition所有的构造方法都要求设置父类名称,所以从代码角度讲,它必须依赖于父类存在,不能单独存在。

spring官方当初设置ChildBeanDefinition的初衷就是永远让它作为一个子bd存在。但是它现在完全可以被GenericBeanDefinition替代了。

继续,再添加一个业务类:

    public class User {
        private String name;
        public void setName(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }
 
    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            //注册配置类
            context.register(Config.class);
    
            //模板BeanDefinition
            RootBeanDefinition root = new RootBeanDefinition();
            //设置为抽象类
            root.setAbstract(true);
            root.setDescription("我是一个模板");
            root.setBeanClass(InterService.class);
            root.getPropertyValues().add("name","源码之路");
            //注册,放到IOC容器中
            context.registerBeanDefinition("interService",root);
            //child继承root
            ChildBeanDefinition child = new ChildBeanDefinition("interService");
            child.setBeanClass(User.class);
            //注册,放到IOC容器中
            context.registerBeanDefinition("child",child);
            context.refresh();
            System.out.println(((User)context.getBean("child")).getName());
    
        }
    }

也就是说User类相当于继承了InterService类,等同于xml文件:

     <bean id="interService" class="com.InterService" > 
         <property name="name" value="源码之路"></property>
    </bean>
    <bean id="user" class="com.User" parent="interService">
    </bean>

这里很绕,笔者当时为了弄懂这里也是费了好大的劲,多读两遍就理解了!

3.RootBeanDefinition:不能设置parentName

一般Spring自己的类会被注册为RootBeanDefinition。

Root,Child根据字面意思,好像是父子关系,AbstractBeanDefinition 中有个属性叫abstract(是否是抽象类),抽象类无法实例化呀,不能保存到beanDefinitionMap容器中啊!有存在的意义吗?

有,模板!

如果一个BeanDefinition中的属性abstract为true,它是让spring来继承它,而不是实例化它。

举个例子吧:

//业务类
public class InterService {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
 

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new 
                                                    AnnotationConfigApplicationContext();
        //注册配置类
        context.register(Config.class);

        //设置父类BeanDefinition 即模板BeanDefinition
        RootBeanDefinition root = new RootBeanDefinition();
        //设置为抽象类
        //这里不一定要设置为true 使用false也是没问题的
        root.setAbstract(true);
        root.setDescription("我是一个模板");
        root.setBeanClass(InterService.class);
        root.getPropertyValues().add("name","源码之路");
        //注册,放到IOC容器中
        context.registerBeanDefinition("interService",root);

        //设置子类BeanDefinition继承RootBeanDefinition
        //interService即Parentname 即父BeanDefinitionName
        //这是ChildBeanDefinition的构造参数
        ChildBeanDefinition child = new ChildBeanDefinition("interService");
        //注册,放到IOC容器中
        context.registerBeanDefinition("child",child);
        context.refresh();
        //获取child的name属性 继承自RootBeanDefinition
            System.out.println
            (((InterService)context.getBean("child")).getName());

    }
}

打印结果:

image.png

RootBeanDefinition不可以替换ChildBeanDefinition

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册配置类
        context.register(Config.class);

        //模板BeanDefinition
        RootBeanDefinition root = new RootBeanDefinition();
        //设置为抽象类
        root.setAbstract(true);
        root.setDescription("我是一个模板");
        root.setBeanClass(InterService.class);
        root.getPropertyValues().add("name","源码之路");
        root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        //注册,放到IOC容器中
        context.registerBeanDefinition("interService",root);

        //使用 RootBeanDefinition代替 childBeanDefinitio
        RootBeanDefinition child = new RootBeanDefinition();
        child.setParentName("interService");
        child.setBeanClass(User.class);
        //注册,放到IOC容器中
        context.registerBeanDefinition("child",child);

        context.refresh();

        System.out.println(((User)context.getBean("child")).getName());
        System.out.println(context.getBeanDefinition("child").getScope());

    }
}

image.png

为什么会报错?

我们看child.setParentName("interService")这行代码的源码。

即RootBeanDefinition的setParentName源码:

  @Override
    public void setParentName(@Nullable String parentName) {
        if (parentName != null) {
            throw new IllegalArgumentException
            	("Root bean cannot be changed into a child bean with parent reference");
        }
    }

看到了吧,你设置父类的时候spring给你抛异常,不允许。RootBeanDefinition的所有构造函数也不给你提供一个设置父类的参数。

那么问题来了,spring为什么这么做?

笔者构建好了spring源码,然后笔者把RootBeanDefinition的源码改了: 首先,在RootBeanDefinition增加一个parentName的属性

@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
      .....
    //父类名称
    private String parentName;
       ....
}

其次,修改setParentName

@Override
    public void setParentName(@Nullable String parentName) {
            //if (parentName != null) {
            //throw new IllegalArgumentException
        //			("Root bean cannot be changed into a child bean with parent reference");
            //}
        this.parentName = parentName;
    }

最后修改getParentName方法,注意,spring原来的就是return null;

 @Override
public String getParentName() {
        //return null;
    return this.parentName;
}

打印结果:

此时,RootBeanDefinition充当了ChildBeanDefinition的角色。

spring为什么这么做?

image.png

不要告诉我setParentName抛异常所以不允许,我已经证明该源码可以了。

我问的是spring源码作者他当时咋想的?

我给你打个样:这里涉及到bean合并。

(18条消息) spring之Bean的生命周期之BeanDefinition的合并解析_kznsbs的博客-CSDN博客

最后读下RootBeanDefinition的源码吧:

    public class RootBeanDefinition extends AbstractBeanDefinition {
        
        //BeanDefinitionHolder存储有Bean的名称、别名数组、BeanDefinition
        //是对BeanDefinition的进一步封装
        @Nullable
        private BeanDefinitionHolder decoratedDefinition;
        
        //AnnotatedElement 是java反射包的接口,通过它可以查看Bean的注解信息
        @Nullable
        private AnnotatedElement qualifiedElement;
        
        //允许缓存
        boolean allowCaching = true;
        
        //从字面上理解:工厂方法是否唯一
        boolean isFactoryMethodUnique = false;
        
        //封装了java.lang.reflect.Type,提供了泛型相关的操作,具体请查看:
        //ResolvableType 可以专题去了解一下子,虽然比较简单 但常见
        @Nullable
        volatile ResolvableType targetType;
        
        //缓存class,表明RootBeanDefinition存储哪个类的信息
        @Nullable
        volatile Class<?> resolvedTargetType;
        
        //缓存工厂方法的返回类型
        @Nullable
        volatile ResolvableType factoryMethodReturnType;

        /** Common lock for the four constructor fields below */
        final Object constructorArgumentLock = new Object();

        //缓存已经解析的构造函数或是工厂方法,Executable是Method、Constructor类型的父类
        @Nullable
        Executable resolvedConstructorOrFactoryMethod;
        
        //表明构造函数参数是否解析完毕
        boolean constructorArgumentsResolved = false;
        
        //缓存完全解析的构造函数参数
        @Nullable
        Object[] resolvedConstructorArguments;
        
        //缓存待解析的构造函数参数,即还没有找到对应的实例,可以理解为还没有注入依赖的形参
        @Nullable
        Object[] preparedConstructorArguments;

        /** Common lock for the two post-processing fields below */
        final Object postProcessingLock = new Object();

        //表明是否被MergedBeanDefinitionPostProcessor处理过
        boolean postProcessed = false;
        
        //在生成代理的时候会使用,表明是否已经生成代理
        @Nullable
        volatile Boolean beforeInstantiationResolved;

        //实际缓存的类型是Constructor、Field、Method类型
        @Nullable
        private Set<Member> externallyManagedConfigMembers;
        
        //InitializingBean中的init回调函数名——afterPropertiesSet会在这里记录,以便进行生命周期回调
        @Nullable
        private Set<String> externallyManagedInitMethods;
        
        //DisposableBean的destroy回调函数名——destroy会在这里记录,以便进行生命周期回调
        @Nullable
        private Set<String> externallyManagedDestroyMethods;

        //===========方法(只例举部分)
        // 由此看出,RootBeanDefiniiton是没有父类的
        @Override
        public String getParentName() {
            return null;
        }
        
        @Override
        public void setParentName(@Nullable String parentName) {
            if (parentName != null) {
                throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
            }
        }
        // 拿到class类型
        @Nullable
        public Class<?> getTargetType() {
            if (this.resolvedTargetType != null) {
                return this.resolvedTargetType;
            }
            ResolvableType targetType = this.targetType;
            return (targetType != null ? targetType.resolve() : null);
        }
        
        @Override
        public RootBeanDefinition cloneBeanDefinition() {
            return new RootBeanDefinition(this);
        }
    }

可以看到许多与反射相关的对象,这说明spring底层采用的是反射机制。

总结一下,RootBeanDefiniiton保存了以下信息:

1. 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
2. Bean的注解(AnnotatedElement)
3. 具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象
4. 构造函数、构造函数形参类型
5. Bean的class对象

可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系。
RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善

4.GenericBeanDefinition:parentName非必需

上文我们说GenericBeanDefinition可以替代RootBeanDefinition和ChildBeanDefinition,原因是GenericBeanDefinition的parentName属性是可以设置也可以不设置,我们测试一下:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册配置类
        context.register(Config.class);
        //模板BeanDefinition
        GenericBeanDefinition root = new GenericBeanDefinition();
        //设置为抽象类
        root.setAbstract(true);
        root.setDescription("我是一个模板");
        root.setBeanClass(InterService.class);
        root.getPropertyValues().add("name","源码之路");
        root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        //注册,放到IOC容器中
        context.registerBeanDefinition("interService",root);

        //child继承root
        GenericBeanDefinition child = new GenericBeanDefinition();
        child.setParentName("interService");
        child.setAbstract(false);
        child.setBeanClass(User.class);
        //注册,放到IOC容器中
        context.registerBeanDefinition("child",child);

        context.refresh();

        System.out.println(((User)context.getBean("child")).getName());
        System.out.println(context.getBeanDefinition("child").getScope());

    }
}

打印结果:

image.png

我们阅读下GenericBeanDefinition源码:

    public class GenericBeanDefinition extends AbstractBeanDefinition {
    
        //父BeanDefinition名字
        @Nullable
        private String parentName;
    
    
        /**
         * 构造方法,所有属性均为空
         */
        public GenericBeanDefinition() {
            super();
        }
    
        /**
         *  从一个给定的BeanDefinition中将属性值copy给新的GenericBeanDefinition
         */
        public GenericBeanDefinition(BeanDefinition original) {
            super(original);
        }
    
    
        //设置父类名称
        @Override
        public void setParentName(@Nullable String parentName) {
            this.parentName = parentName;
        }
        //获取父类名称
        @Override
        @Nullable
        public String getParentName() {
            return this.parentName;
        }
    
        //根据当前GenericBeanDefinition克隆一个新的GenericBeanDefinition
        @Override
        public AbstractBeanDefinition cloneBeanDefinition() {
            return new GenericBeanDefinition(this);
        }
    
        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (!(other instanceof GenericBeanDefinition)) {
                return false;
            }
            GenericBeanDefinition that = (GenericBeanDefinition) other;
            return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName)
                            && 
                            super.equals(other));
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("Generic bean");
            if (this.parentName != null) {
                sb.append(" with parent '").append(this.parentName).append("'");
            }
            sb.append(": ").append(super.toString());
            return sb.toString();
        }
    
    }

我们来做个总结吧:

  • RootBeanDefinition作为父bd出现,不能作为子bd出现。

  • ChildBeanDefinition必须作为子bd出现。

  • GenericBeanDefinition可以作为父bd出现,也可以作为子bd出现。它可以完全替代ChildBeanDefinition,但不能完全替代RootBeanDefinition,这一点在以后的bean合并博文中会讲解,敬请期待。

现如今,大家都用spring注解扫描的方式进行开发,首先在业务类上添加一个注解,比如@Service、@Controller、@Component等,spring扫描所有类并判断是否加入相关注解,有注解的类会生成一个BeanDefinition并添加到IOC容器中。我们称它为注解BeanDefinition即AnnotatedBeanDefinition。 AnnotatedBeanDefinition是一个注解bd的接口,可以获取BeanDefinition注解相关数据。

它有3个实现类:

ScannedGenericBeanDefinition

AnnotatedGenericBeanDefinition

ConfigurationClassBeanDefinition

5.ScannedGenericBeanDefinition:扫描注解生成的BD

被@Component注解的类,会生成ScannedGenericBeanDefinition类型的BeanDefinition。

其它继承了@Component的注解如@Service、@Controller、@Repository @Configuration

注意@Configuration注解上有@Component注解

也会生成ScannedGenericBeanDefinition类型的Bean定义。

    ScannedGenericBeanDefinition extends GenericBeanDefinition 
                                            implements AnnotatedBeanDefinition

ScannedGenericBeanDefinition实现了AnnotatedBeanDefinition接口且继承了GenericBeanDefinition类,scan翻译成中文就是扫描的意思,顾名思义,它就是spring的Scaner扫描后生成的BeanDefinition。

//业务类
@Component
@Description("业务类")
@Scope("singleton")
public class InterService {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

//测试类
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new 
                                    AnnotationConfigApplicationContext();
        //注册配置类
        context.register(Config.class);
        context.refresh();
        ScannedGenericBeanDefinition beanDefinition 
            = (ScannedGenericBeanDefinition) context.getBeanDefinition("interService");
        //查看spring给我生成的具体BeanDefinition类型
        System.out.println(beanDefinition.getClass().getSimpleName());
        //获取注解信息
        AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
        //获取工厂方法元数据
        MethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata();
        System.out.println();
    }
}

测试结果:

image.png

6.AnnotatedGenericBeanDefinition

AnnotatedBeanDefinitionReader注册的BD

通过AnnotatedBeanDefinitionReader的register方法注册上去的BeanDefinition

AnnotatedBeanDefinition接口源码很容易理解:

    public interface AnnotatedBeanDefinition extends BeanDefinition {
        /**
         * 获取bean上的所有的注解信息 如@Component
         */
        AnnotationMetadata getMetadata();
        /**
         * 获取此bean的工厂方法的元数据(如果有)。
         */
        @Nullable
        MethodMetadata getFactoryMethodMetadata();
    }

这两个方法是在子类中实现的,我们先查看这两个方法返回的具体信息:

AnnotationMetadata你就理解为存储了业务类的注解信息,便于spring后续的解析

spring启动时会生成一个AnnotatedBeanDefinitionReader读取器:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new 
                                    AnnotationConfigApplicationContext();
        //注册配置类
        context.register(Config.class);
        context.refresh();
        System.out.println
                    (context.getBeanDefinition
                                ("interService").getClass().getSimpleName());

        System.out.println();
    }
}

public AnnotationConfigApplicationContext() {
        //在IOC容器中初始化一个 注解bean读取器AnnotatedBeanDefinitionReader
        this.reader = new AnnotatedBeanDefinitionReader(this);
        //在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

AnnotatedGenericBeanDefinition的加载过程

其实都是通过AnnotatedBeanDefinitionReader的register方法注册上去的。

自定义加载配置类

主要看这行代码: context.register(Config.class);

查看以下源码:

context.register(Config.class)
        ->this.reader.register(componentClasses);
            ->registerBean(componentClass);
                ->doRegisterBean(beanClass, null, null, null);
                    ->doRegisterBean()

最后跟到doRegisterBean方法:

//第一行代码
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
      .......中间省略........
//最后一行代码,注册到IOC容器 definitionHolder就是封装了BeanDefinition的对象 registry是容器
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

spring将你的配置定生成了一个AnnotatedGenericBeanDefinition。 我们来测试一下:

    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new    
                                    AnnotationConfigApplicationContext();
            //注册配置类
            context.register(Config.class);
            context.refresh();
            System.out.println
                    (context.getBeanDefinition("config").getClass().getSimpleName());
            System.out.println();
        }
    }
    //打印结果:
    //AnnotatedGenericBeanDefinition

自定义加载自定义类

其实就跟上面配置类一样。我们不让spring自动扫描,我们手动注册一个业务类。

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册配置类
        context.register(Config.class);
        context.refresh();

        //手动注册一个业务类
        context.register(InterService.class);
        System.out.println
            (context.getBeanDefinition
                ("interService").getClass().getSimpleName());
        System.out.println();
    }
}
//打印结果:
//AnnotatedGenericBeanDefinition

7.ConfigurationClassBeanDefinition

带@Bean方法被处理为ConfigurationClassBeanDefinition

首先需要注意的是,ConfigurationClassBeanDefinition是一个内部类,其外部类是ConfigurationClassBeanDefinitionReader,ConfigurationClassBeanDefinitionReader这个类负责将被@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类,源码就不过多解释了,和之前几个BeanDefinition差不多。

默认设置

  • 如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean。

  • @Configuration注解的类会成为一个代理类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化。

  • @Bean注解注释的类会使用构造函数自动装配。

  • @Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法。并且这个@Bean注解的方法返回的实例和直接调用@Configuration注解的类的中的@Bean方法是1个!也就是是1个单例!

  • @Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会被代理,具体代码在

//策略是CglibSubclassingInstantiationStrategy继承自SimpleInstantiationStrategy
//具体看SimpleInstantiationStrategy#instantiate
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
//代理类的增强逻辑
//ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
package parse;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
public class Config {
    public Config() {
        System.out.println("------------------------Config实例化了");
    }

    @Bean
    public  User getUser(){
          return new User();
    }
}
    package parse;
    
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.support.GenericBeanDefinition;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
    
    public class ParseTest {
        public static void main(String[] args) throws InterruptedException {
            start1();
        }
        
         public static void start1() {
            //其中Config.class可以指定为
            //包扫描启动:@ComponentScan("tyrant")
            //使用xml文件启动:@ImportResource("applicationContext.xml")
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
             //注册配置类
            context.register(Config.class);
            context.refresh();
             Config config = (Config) context.getBean("config");
             Object user = context.getBean("getUser");
             System.out.println(config.getUser()== user);
         }
    }
    //结果是true 说明从容器中获取的对象和直接调用config.getUser()获取的对象是同一个对象

说明从容器中获取的对象和直接调用config.getUser()获取的对象是同一个对象

    package tyrant.user;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class User {
    
        @Bean
        public User getUser() {
            return new User();
        }
    
        private int age = 31;
    
        private String name = "user";
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    package tyrant;
    
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.support.ChildBeanDefinition;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ScannedGenericBeanDefinition;
    import org.springframework.core.Ordered;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.core.type.MethodMetadata;
    
    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            //注册配置类
            context.register(BeanAnnotationConfig.class);
            context.refresh();
            //返回的是getUser方法对应的beanDefinition
            BeanDefinition beanDefinition =  context.getBeanDefinition("getUser");
            //返回的是User对应的beanDefinition
            BeanDefinition definition =  context.getBeanDefinition("user");
            //查看spring给我生成的具体BeanDefinition类型
            System.out.println(beanDefinition.getClass().getSimpleName());
            System.out.println(definition.getClass().getSimpleName());
        }
    }
    
    //ConfigurationClassBeanDefinition
    //ScannedGenericBeanDefinition

@Bean注解生成的BeanDefinition是ConfigurationClassBeanDefinition @Configuration生成的是ScannedGenericBeanDefinition。 @Configuration注解上有@Component注解

至此,BeanDefinition整个家族继承关系讲完了,相信认真读过这三篇博文的读者对BeanDefinition都有深入的理解了,建议读者结合这三篇博文认真练习,BeanDefinition打好基础了后续spring源码的阅读才会游刃有余,否则很难读下去。

笔者相信,BeanDefinition中的很多属性大家都不是很理解在spring中到底起了什么作用,这个没关系,在后续源码学习过程中这些属性的作用会慢慢浮出水面,到时候再回过头复习才会恍然大悟。

总结

通过AnnotatedBeanDefinitionReader注册的类sping都会生成AnnotatedGenericBeanDefinition。

通过注解被Spring自动扫描的都会生成ScannedGenericBeanDefinition。

被@Component注解的类,其它继承了@Component的注解如@Service、@Controller、@Repository @Configuration都会生成ScannedGenericBeanDefinition类型的BeanDefinition。

被@Bean注解的方法会被转换为对应的ConfigurationClassBeanDefinition