4.BeanDefinition的实现类详解


highlight: arduino-light

theme: juejin

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

1.AbstractBeanDefinition

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

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

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

```java //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,把钉钉、企微、飞书的参数都放进去。

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

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

public static void warnPush(WarnPushDTO dto)

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

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

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

java @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

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

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

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

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

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

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

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

等同于xml文件中的配置:

java <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是对象的属性比如年龄、身高等。

java //设置属性值 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不能独立存在,他必须继承一个父类,为什么?我们看源码:

```java 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替代了。

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

```java 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文件:

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来继承它,而不是实例化它。

举个例子吧:

```java //业务类 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的属性

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

其次,修改setParentName

java @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的源码吧:

```java 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源码:

```java 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定义。

java ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition

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

```java //业务类 @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接口源码很容易理解:

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

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

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

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

```java 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);

查看以下源码:

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

最后跟到doRegisterBean方法:

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

```java 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。 我们来测试一下:

java 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自动扫描,我们手动注册一个业务类。

```java 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

```java 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();
}

} ```

```java 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()获取的对象是同一个对象

```java 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;
    }
}

```

```java 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值