【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 我就看到这里哈,有理解不对的地方欢迎指正哈。