逐行阅读Spring5.X源码(三) BeanDefinition的实现类详解,拔高

时间:2022-07-24
本文章向大家介绍逐行阅读Spring5.X源码(三) BeanDefinition的实现类详解,拔高,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

书接上回。

上回咱们讲了BeanDefinition的父接口及父接口实现类。本篇博文咱么继续讲BeanDefinition的实现类。包括AbstractBeanDefinition、RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition、AnnotateGenericBeanDefinition、ScannerGenericBeanDefinition。

1. AbstractBeanDefinition

AbstractBeanDefinition是抽象类,它是众多子类的父类。前两篇文章讲的BeanDefinition属性值大都保存在AbstractBeanDefinition,并实现了子BeanDefinition通用方法。同时它也继承了BeanMetadataAttributeAccessor完成attribute和source的操作。我们看一下它的关键源码:

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
        implements BeanDefinition, Cloneable {
        
    // 此处省略静态变量以及final变量
    
    @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;
    /**
     * autowire-candidate属性设置为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;
    /**
     * 对应bean属性factory-bean,用法:
     * <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
     * <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
     */
    @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,程序设置
     */
    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 就是保存了属性值并对属性值进行设置和读取。记住这一点就行了。当然,有的读者说,源码很简单,但是里面的属性值具体代表啥意思呢?在什么时候用到呢?前两篇博文我说了,我讲解BeanDefinition这块内容就是让大家纯粹的理解BeanDefition的作用,BeanDefition是整个spring源码中的基础。在以后的学习中,BeanDefinition中的属性值作用会慢慢的浮出水面,大家不要着急。 AbstractBeanDefinition 其实已经涵盖了所有属性了,spring为什么要提供这么多的子类?正所谓,既生瑜何生亮!笔者认为,完全可以用一个AbstractBeanDefinition 代替所有的子类,只不过spring为了模块化,不同的BeanDefinition可能从代码角度来讲都一样,但是从设计角度来讲我们要模块化,要拆分,不通模块的BeanDefinition无论从设计还是功能肯定有差异,我们当然可以将这些差异规避在AbstractBeanDefinition ,但是这不利于维护和扩展,更不利于阅读理解。 我们看一下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。

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
        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");
        //注册,放到IOC容器中
        context.registerBeanDefinition("child",child);
        context.refresh();
    System.out.println(((InterService)context.getBean("child")).getName());

    }
}

打印结果:

这里讲一下这行代码:

        root.getPropertyValues().add("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>

如果,我设置了一个业务类中不存在的属性,就会报错,比如:

我说过,AbstractBeanDefinition中的属性以后都会讲到,别急,这个propertyValues只到啥意思了吧? 继续,再添加一个业务类:

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());

    }
}

我们只是增加了child.setBeanClass(User.class);这行代码 打印结果:

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

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

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

2. GenericBeanDefinition

上文我们说GenericBeanDefinition可以替代RootBeanDefinition和ChildBeanDefinition,我们测试一下:

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());

    }
}

打印结果:

我们阅读下GenericBeanDefinition源码:

public class GenericBeanDefinition extends AbstractBeanDefinition {

    //父BeanDefinition名字
    @Nullable
    private String parentName;


    /**
     * Create a new GenericBeanDefinition, to be configured through its bean
     * properties and configuration methods.
     * @see #setBeanClass
     * @see #setScope
     * @see #setConstructorArgumentValues
     * @see #setPropertyValues
     * 构造方法,所有属性均为空
     */
    public GenericBeanDefinition() {
        super();
    }

    /**
     * Create a new GenericBeanDefinition as deep copy of the given
     * bean definition.
     * @param original the original bean definition to copy from
     *  从一个给定的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();
    }

}

3. RootBeanDefinition

但是,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);

        //child继承root
        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());

    }
}

为什么?我们看child.setParentName("interService")这行代码的源码:

    @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为什么这么做?不要告诉我setParentName抛异常所以不允许,我已经证明该源码可以了,我问的是spring源码作者他当时咋想的?我给你打个样:这里涉及到bean合并。 最后读下RootBeanDefinition的源码吧:

public class RootBeanDefinition extends AbstractBeanDefinition {
    
    //BeanDefinitionHolder存储有Bean的名称、别名、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. ChildBeanDefinition

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

public class ChildBeanDefinition extends AbstractBeanDefinition {

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


    /**
     * Create a new ChildBeanDefinition for the given parent, to be
     * configured through its bean properties and configuration methods.
     * @param parentName the name of the parent bean
     * @see #setBeanClass
     * @see #setScope
     * @see #setConstructorArgumentValues
     * @see #setPropertyValues
     * 构造函数,必须设置一个父类
     */
    
    public ChildBeanDefinition(String parentName) {
        super();
        this.parentName = parentName;
    }

    /**
     * Create a new ChildBeanDefinition for the given parent.
     * @param parentName the name of the parent bean
     * @param pvs the additional property values of the child
     * 构造函数,设置父类和业务类属性   
     */
    public ChildBeanDefinition(String parentName, MutablePropertyValues pvs) {
        super(null, pvs);
        this.parentName = parentName;
    }

    /**
     * Create a new ChildBeanDefinition for the given parent.
     * @param parentName the name of the parent bean
     * @param cargs the constructor argument values to apply
     * @param pvs the additional property values of the child
     * 构造函数,设置父类,业务类构造函数的参数,业务类属性   
     */
    public ChildBeanDefinition(
            String parentName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {

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

    /**
     * Create a new ChildBeanDefinition for the given parent,
     * providing constructor arguments and property values.
     * @param parentName the name of the parent bean
     * @param beanClass the class of the bean to instantiate
     * @param cargs the constructor argument values to apply
     * @param pvs the property values to apply
     * 构造函数,设置父类,业务类beanClass,业务类构造函数的参数,业务类属性      
     */
    public ChildBeanDefinition(
            String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {

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

    /**
     * Create a new ChildBeanDefinition for the given parent,
     * providing constructor arguments and property values.
     * Takes a bean class name to avoid eager loading of the bean class.
     * @param parentName the name of the parent bean
     * @param beanClassName the name of the class to instantiate
     * @param cargs the constructor argument values to apply
     * @param pvs the property values to apply
     * 构造函数,设置父类,业务类名称,业务类构造函数的参数,业务类属性   
     */
    public ChildBeanDefinition(
            String parentName, String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {

        super(cargs, pvs);
        this.parentName = parentName;
        setBeanClassName(beanClassName);
    }

    /**
     * Create a new ChildBeanDefinition as deep copy of the given
     * bean definition.
     * @param original the original bean definition to copy from
     * 构造函数,从另一个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替代了。

我们来做个总结吧:

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

5. AnnotatedBeanDefinition

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

public interface AnnotatedBeanDefinition extends BeanDefinition {
    /**
     * Obtain the annotation metadata (as well as basic class metadata)
     * for this bean definition's bean class.
     * @return the annotation metadata object (never {@code null})
     * 获取注解信息
     */
    AnnotationMetadata getMetadata();
    /**
     * Obtain metadata for this bean definition's factory method, if any.
     * @return the factory method metadata, or {@code null} if none
     * @since 4.1.1
     * 获取此beanDefinition的工厂方法的元数据(如果有)。
     */
    @Nullable
    MethodMetadata getFactoryMethodMetadata();

}

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

//业务类
@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();
    }
}

测试结果:

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

6. ScannedGenericBeanDefinition

有@Component注解的类,会生成ScannedGenericBeanDefinition类型的Bean定义。注意其它继承了@Component的注解如@Service、@Controller、@Repository也是生成ScannedGenericBeanDefinition类型的Bean定义。 ScannedGenericBeanDefinition实现了AnnotatedBeanDefinition接口且继承了GenericBeanDefinition类,scan翻译成中文就是扫描的意思,顾名思义,它就是spring扫描后生成的BeanDefinition。它的源码也很容易理解,读者自行查阅。

7.AnnotatedGenericBeanDefinition

AnnotatedGenericBeanDefinition在两种地方会使用。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);
    }
  1. 解析配置类 主要看这行代码: 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容器
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

看到了码,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
  1. 手动注册 其实就跟上面配置类一样。我们不让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

总结:通过AnnotatedBeanDefinitionReader手动注册的类sping都会生成AnnotatedGenericBeanDefinition。而自动扫描的都会生成ScannedGenericBeanDefinition。

8.ConfigurationClassBeanDefinition

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

默认设置

  1. 如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean。
  2. @Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化。
  3. @Bean注解注释的类会使用构造函数自动装配。
//在@Configuration注解的类中,使用@Bean注解实例化的Bean,其定义会用ConfigurationClassBeanDefinition存储。
@Configuration
public class ConfigurationTest {
    @Bean
    public User getUser(){
        return new User();
    }
}

public class User {
    private String name;
}

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

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

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