【Spring】BeanDefinition 源码深度解析

1  前言

今天想细细研究下 BeanDefinition,至于为什么,主要是看了很多遍,没太关注 mergedBeanDefinition 所以比较好奇,它是干啥的呢?所以得先搞清 BeanDefinition,开整。

2  源码分析

我们得先知道 BeanDefinition 在 Spring 这个大框架下是个什么位置。我的理解它就类似于 Java 中的类(Class),在 Java 中,Class 是创建对象的模板,那 BeanDefinition 就是创建生成 Bean的模板。

Spring 中我大概理解为三层或者四层吧:BeanDefinition 生成 Bean 实例,Bean实例交给 BeanFactory 管理,BeanFactory 交给 ApplicationContext 提供基础服务。

知道它的位置后,我们接下来先看看它内部有哪些属性和方法,然后看它的上下类图大概划分为哪些类型的 BeanDefinition,然后看看常规下 SpringBoot 启动下不同的 Bean 方式都转换为了哪些 BeanDefinition。

2.1  BeanDefinition 接口

我们首先来看看该接口都有哪些东西:

/**
 * BeanDefinition 描述了一个 Bean 实例(包含属性、构造器、关系)
 * A BeanDefinition describes a bean instance, which has property values,
 * constructor argument values, and further information supplied by
 * concrete implementations.
 * 可以通过 BeanFactoryPostProcessor 改变属性以及其他元信息
 * <p>This is just a minimal interface: The main intention is to allow a
 * {@link BeanFactoryPostProcessor} to introspect and modify property values
 * and other bean metadata.
 * @see ConfigurableListableBeanFactory#getBeanDefinition
 * @see org.springframework.beans.factory.support.RootBeanDefinition
 * @see org.springframework.beans.factory.support.ChildBeanDefinition
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    /**
     * 作用范围:单例、多例
     * isSingleton 判断是不是单例
     * isPrototype 判断是不是多例
     * 通过 setScope/getScope 获取修改作用范围
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    boolean isSingleton();
    boolean isPrototype();
    void setScope(@Nullable String scope);
    @Nullable
    String getScope();

    /**
     * 三个角色类型
     * ROLE_APPLICATION 表示这个 Bean 是用户自己定义的 Bean
     * ROLE_SUPPORT 表示这个 Bean 是某些复杂配置的支撑部分
     * ROLE_INFRASTRUCTURE 表示这是一个 Spring 内部的 Bean
     * 通过 setRole/getRole 可以修改
     */
    int ROLE_APPLICATION = 0;
    int ROLE_SUPPORT = 1;
    int ROLE_INFRASTRUCTURE = 2;
    void setRole(int role);
    int getRole();

    /**
     * parentName 说明 BeanDefinition 存在父子继承的关系 即类似类里的继承关系 extends
     * 通过 setParentName/getParentName 可以修改
     */
    void setParentName(@Nullable String parentName);
    @Nullable
    String getParentName();

    /**
     * 表示当前 BeanDefinition 的类型,全类名
     */
    void setBeanClassName(@Nullable String beanClassName);
    @Nullable
    String getBeanClassName();

    /**
     * 延迟初始化 <bean lazy-init="">
     * lazyInit = true 表示用到的时候才创建
     */
    void setLazyInit(boolean lazyInit);
    boolean isLazyInit();

    /**
     * 依赖列表 <bean depends-on=""> @DependsOn
     */
    void setDependsOn(@Nullable String... dependsOn);
    @Nullable
    String[] getDependsOn();

    /**
     * 是否自动装配
     */
    void setAutowireCandidate(boolean autowireCandidate);
    boolean isAutowireCandidate();

    /**
     * 是否抽象的
     */
    boolean isAbstract();
    /**
     * 是否主要的首选的 也就是当存在多个的时候,优先取的
     */
    void setPrimary(boolean primary);
    boolean isPrimary();

    /**
     * factoryBean 相关的
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);
    @Nullable
    String getFactoryBeanName();
    void setFactoryMethodName(@Nullable String factoryMethodName);
    @Nullable
    String getFactoryMethodName();

    /**
     * Bean 构造方法的参数,用于实例化 Bean 判断
     */
    ConstructorArgumentValues getConstructorArgumentValues();
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }

    /**
     * Bean 属性列表
     */
    MutablePropertyValues getPropertyValues();
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }

    /**
     * Bean 初始化方法 @Bean(initMethod="init")来指定初始化方法 类似 @PostConstruct
     */
    void setInitMethodName(@Nullable String initMethodName);
    @Nullable
    String getInitMethodName();

    /**
     * Bean 销毁方法  @Bean(destroyMethod = "") 类似 @PreDestory
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);
    @Nullable
    String getDestroyMethodName();

    /**
     * 描述信息 类似订单的备注
     */
    void setDescription(@Nullable String description);
    @Nullable
    String getDescription();

    /**
     * 资源描述 还是描述信息 类似订单的商家备注
     */
    @Nullable
    String getResourceDescription();

    /**
     * Return a resolvable type for this bean definition,
     * based on the bean class or other specific metadata.
     * <p>This is typically fully resolved on a runtime-merged bean definition
     * but not necessarily on a configuration-time definition instance.
     * @return the resolvable type (potentially {@link ResolvableType#NONE})
     * @since 5.2
     * @see ConfigurableBeanFactory#getMergedBeanDefinition
     */
    ResolvableType getResolvableType();

    /**
     * Return the originating BeanDefinition, or {@code null} if none.
     * <p>Allows for retrieving the decorated bean definition, if any.
     * <p>Note that this method returns the immediate originator. Iterate through the
     * originator chain to find the original BeanDefinition as defined by the user.
     */
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();
}

上边的注释,我是把一些属性和方法归了下类,大概有这么几块是我们需要关注的:

(1)单例还是多例的:scope、isSingleton、isPrototype

(2)BeanDefinition 类型划分:role 主要区分是框架内部的还是用户自定义的

(3)父子关系:parentName,说明 BeanDefinition 存在父子关系,也就说明某些属性可以继承类似 extends

(4)class 类型:beanClassName,Bean 表现的 class

(5)属性:ConstructorArgumentValues 构造器属性(用于创建实例)、MutablePropertyValues 属性字段(用于类型注入等)

(6)钩子函数:initMethodName (初始化方法)、destoryMethodName (销毁方法)

(7)实例化时机:lazyInit 比如 spring的 refresh 当 = false 的时候会提前创建出来

2.2  实现类以及SpringBoot 启动下的 BeanDefinition

看完它有的内部结构后,我们看看它的实现类:

可以看到 AbstractBeanDefinition 作为底座的,大概分三个派系:

(1)常规派:以 GenericBeanDefinition 为首的

(2)注解派:以 AnnotatedBeanDefinition 为首的

(3)根派的:RootBeanDefinition (这个不常用了)

(4)父子派的:ChildBeanDefinition(这个也不常用了)

我们先不解释每个类型的 BeanDefinition,太枯燥了,我们直接先看下 SpringBoot 启动完后,BeanFactory 里都有哪些类型的 BeanDefinition,在哪看呢?其实它存储在 BeanFactory 的实现里:

可以看到有179个 BeanDefinition,在看看有哪些类型的:

(1)org.springframework.beans.factory.support.RootBeanDefinition 比如internalCommonAnnotationProcessor、internalEventListenerProcessor、internalAutoProxyCreator都是些 spring 内部的高级类

(2)org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$ConfigurationClassBeanDefinition @Configuration里的Bean 比如 SqlSessionTemplate、SqlSessionFactory

(3)org.springframework.context.annotation.ScannedGenericBeanDefinition 扫描型的注解比如我们写的 Controller、Service、@Component的工具类等、还有 Mapper 接口

(4)org.springframework.beans.factory.support.ChildBeanDefinition 就一个我自己的类= = 看来这个不常用了

(5)org.springframework.beans.factory.support.GenericBeanDefinition 比如 MybatisPlusProperties、WebMvcProperties、ServerProperties、JdbcProperties 等属性配置类还有一些 spring 内部类

(6)org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition 比如 MybatisPlusAutoConfiguration、RestTemplateAutoConfiguration 基本的自动装配类、还有带@Configuration 的

除了 Root 和 Child 的这两个比较少,其他四个都比较多。

从上边的规律大概能猜出我们平时自定义的一些比如 @Component、@Controller、@Service、@Mapper 基本都转为了 ScannedGenericBeanDefinition , @Configuration 配置类基本转为 AnnotatedGenericBeanDefinition,@Configuration 里的@Bean 基本转为了 ConfigurationClassBeanDefinition ,我们的属性配置类基本转为了普通的 GenericBeanDefinition 。

2.3  AbstractBeanDefinition

我们就来看看底座 AbstractBeanDefinition,东西还挺多,这个类就一千多行的代码,从属性上下手,粗略看了一下以及我之前看源码的过程,大概多了一个重要的属性就是装配模式:autowireMode,这个就跟我们看 Mybatis 代理创建过程里的 SqlSessionTemplate 里的属性 SqlSessionFactory 能自动赋值,就呼应上了。

autowireMode:默认的都是 no,也就是不装配,1是根据名称 2 是根据类型 3是构造器,mybatis那里就是设置的 2,类型装配根据 set方法设置进去的。

其他方法的话,就不看了哈,没什么大特殊的,先不追那么细了。

2.4  GenericBeanDefinition

GenericBeanDefinition 是从 Spring2.5 以后新加入的 BeanDefinition 实现类。GenericBeanDefinition 可以动态设置父 Bean,同时兼具 RootBeanDefinition 和 ChildBeanDefinition 的功能,因此,自从有了 GenericBeanDefinition 之后,RootBeanDefinition 和 ChildBeanDefinition 现在相对就用的少了。我们看上边,我们大多的属性配置都会包装成 GenericBeanDefinition ,我这里就从 MybatisPlus 的配置看看源码:

那我们继续看下注解 @EnableConfigurationProperties:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EnableConfigurationPropertiesRegistrar.class})
public @interface EnableConfigurationProperties {
    String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";

    Class<?>[] value() default {};
}

可以看到引入了 EnableConfigurationPropertiesRegistrar 属性配置注册器:

class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
    EnableConfigurationPropertiesRegistrar() {
    }
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        registerInfrastructureBeans(registry);
        // 交给 ConfigurationPropertiesBeanRegistrar 注册
        ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
        this.getTypes(metadata).forEach(beanRegistrar::register);
    }
    ...
}

继续跟进 ConfigurationPropertiesBeanRegistrar :

final class ConfigurationPropertiesBeanRegistrar {
    private final BeanDefinitionRegistry registry;
    private final BeanFactory beanFactory;

    ConfigurationPropertiesBeanRegistrar(BeanDefinitionRegistry registry) {
        this.registry = registry;
        this.beanFactory = (BeanFactory)this.registry;
    }

    void register(Class<?> type) {
        MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class);
        this.register(type, annotation);
    }

    void register(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
        String name = this.getName(type, annotation);
        if (!this.containsBeanDefinition(name)) {
            // 注册 BeanDefinition
            this.registerBeanDefinition(name, type, annotation);
        }

    }
    ...

    private void registerBeanDefinition(String beanName, Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
        Assert.state(annotation.isPresent(), () -> {
            return "No " + ConfigurationProperties.class.getSimpleName() + " annotation found on  '" + type.getName() + "'.";
        });
        // 创建 BeanDefinition 并注册
        this.registry.registerBeanDefinition(beanName, this.createBeanDefinition(beanName, type));
    }
   
    private BeanDefinition createBeanDefinition(String beanName, Class<?> type) {
        if (BindMethod.forType(type) == BindMethod.VALUE_OBJECT) {
            return new ConfigurationPropertiesValueObjectBeanDefinition(this.beanFactory, beanName, type);
        } else {
            // 可以看到使用 常规的 BeanDefinition 包装的
            GenericBeanDefinition definition = new GenericBeanDefinition();
            definition.setBeanClass(type);
            return definition;
        }
    }
}

2.5  ScannedGenericBeanDefinition 、AnnotatedGenericBeanDefinition 、ConfigurationClassBeanDefinition 

这三个就比较牛逼了,它们不仅继承了常规,还实现了注解的接口,都是常规以及注解的结合体。

那我们刚看的 Controller、Service、Mapper什么的都包装成了 ScannedGenericBeanDefinition ,@Configuration以及一些自动装配类都包装成了 @AnnotatedGenericBeanDefinition ,@Configuration 里的@Bean 都包装成了 ConfigurationClassBeanDefinition 。

他们是怎么注入的,这就要看一个比较重要的大杀器类 ConfigurationClassPostProcessor,这个家伙着实牛逼。如下图:

首先扫描出基础包下以及 SPI 自动配置类下的很多类逐步分析加载他们的 BeanDefinition。

这里先看看我们 Controller、Service的过程,源码就不带着大家一步一步看了哈,我这里画了个图来看下:

然后我们再看看 @Configuration 里的 Bean的生成,一样我画个图哈:

2.6  RootBeanDefinition、ChildBeanDefinition

这两个目前用的比较少了,我这里拿这两个举个例子,体会一下,仅举例,GenericBeanDefinition 同样也可以的。

public static void main(String[] args) {
    ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
    DefaultListableBeanFactory beanFactory = ((DefaultListableBeanFactory) applicationContext.getBeanFactory());
    // 注册一个 root 的  name=root code=root
    RootBeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClass(AccountPo.class);
    beanDefinition.getPropertyValues().add("name", "root");
    beanDefinition.getPropertyValues().add("code", "root");
    beanFactory.registerBeanDefinition("person", beanDefinition);
    // 注册一个儿子的 继承 person root型的 形成父子关系
    ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("person");
    childBeanDefinition.setBeanClass(AccountPo.class);
    // 设置自己个性的 name=child
    childBeanDefinition.getPropertyValues().add("name", "child");
    beanFactory.registerBeanDefinition("child", childBeanDefinition);
    AccountPo accountPo = beanFactory.getBean("child", AccountPo.class);
    // 打印下儿子
    System.out.println(accountPo);
}

继承了父亲的属性还能个性化自己的。

3  问题

3.1  我们的启动类包装成了什么 BeanDefinition?

这个它什么时候注入的 BeanDefinition,我有点忘了,我就在这里打了个断点:

通过 AnnotatedBeanDefinitionReader 注解的 Reader 注入进来的,可以看到包装成了 AnnotatedGenericBeanDefinition:

那么也可以看到通过 AnnotatedBeanDefinitionReader 注入的 Bean 基本都是 AnnotatedGenericBeanDefinition 类型的。

3.2  getMergedLocalBeanDefinition

回到我最初的疑惑,就是 doGetBean 的时候,有一个 getMergedLocalBeanDefinition 的操作,有一个合并的操作,他会把一些 BeanDefinition 用 RootBeanDefinition 包装一下:

我们自己定义的一些Bean 都被包装了一层,这个具体是为什么?我百度了一下说是为了兼容以前老版本的 RootBeanDefinition 什么的。这块就不太清楚了哈,有知道的还望告知哈。

4  小结

好啦,关于 BeanDefinition 我就看到这里哈,有理解不对的地方欢迎指正哈。

posted @ 2024-03-11 09:58  酷酷-  阅读(122)  评论(0编辑  收藏  举报