【源码】Spring —— BeanDefinition 解读1
前言
BeanDefinition
是 Spring
中对所有 Bean
实例的基础定义信息,一般在 容器 生命周期的很早期就注册了大量的 BeanDefinition
,因而后续的各种 Bean
实例依此创建,用官方的话来说 BeanDefinition
就是 bean
的菜单
Spring IoC Container
基于 BeanDefinition
创建 bean
,但并不意味着容器中的 bean 就有对应的 BeanDefinition
,比如 registerSingleton
方法注册的单例
版本
Spring 5.2.x
BeanDefinition
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 单例常量
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
// 原型常量
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// BeanDefinition 的角色常量定义
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
// bean definition 也有“父子”关系
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
// bean 实例的类属性指定
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
// bean 实例的 Scope(作用域)指定
void setScope(@Nullable String scope);
@Nullable
String getScope();
// 是否懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 该 bean 的初始化依赖哪些 bean(即被依赖 bean 的初始化会先于当前 bean)
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
/**
* 标记此 bean 是否可以作为被注入的候选对象
* 注意,这个标志只影响基于类型的自动装配,也就是说:
* 即使该 bean 没有被标记,按名称自动装配仍然可以被注入
*/
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 针对多个 备选注入 bean 的情况,是否是唯一备选(比如 @Primary 注解)
void setPrimary(boolean primary);
boolean isPrimary();
// 工厂方法对应的 bean 的名称
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
// 工厂方法名,对应的就是基于工厂方法创建 bean 的模式
// 比如 @Bean 形式创建的 bean 实例
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
// 返回构造方法参数,对应 构造方法 注入依赖的模式
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// 属性值集合,对应 属性 注入依赖的模式
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// 初始化回调方法名
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
// 销毁回调方法名
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
// 角色设置
void setRole(int role);
int getRole();
// bean definition 描述
void setDescription(@Nullable String description);
@Nullable
String getDescription();
// 获取对应的 ResolvableType
ResolvableType getResolvableType();
// 是否单例
boolean isSingleton();
// 是否原型
boolean isPrototype();
// 是否抽象类
boolean isAbstract();
@Nullable
// BeanDefinition 所在的资源描述信息,报错是提示用
String getResourceDescription();
@Nullable
// 返回被“装饰”的“最近”的 BeanDefinition
// 比如代理 BeanDefinition 会将 targetBeanDefinition 存放到 decoratedDefinition 属性
BeanDefinition getOriginatingBeanDefinition();
}
BeanDefinition
的顶层接口,对一个 bean
的描述清单,比如:
Class
:bean
实例的类信息Name
:bean
实例的名称信息,涉及别名的指定Scope
:bean
实例的作用域信息,关系到它的生命周期Constructor arguments
:以构造方法形式注入依赖时的参数Properties
:以属性形式注入依赖时的参数Autowiring mode
:自动注入bean
实例依赖的模式Lazy initialization mode
:bean
实例是否延迟加载Initialization method
:init
回调方法指定Destruction method
:destroy
回调方法指定
拓展
如上是 BeanDefinition
的继承图:
AbstractBeanDefinition
作为BeanDefinition
的抽象实现,提供了通用方法的实现RootBeanDefinition
和ChildBeanDefinition
是一组可以拥有父子关系的BeanDefinition
GenericBeanDefinition
是最通用的BeanDefinition
,它的属性parentName
同样可以指向父BeanDefinition
AnnotatedBeanDefinition
是BeanDefinition
的子接口,它在BeanDefinition
的基础上提供了AnnotationMetadata getMetadata()
MethodMetadata getFactoryMethodMetadata()
两个方法用于获取AnnotationMetadata
和MethodMetadata
AnnotatedGenericBeanDefinition
,AnnotatedBeanDefinition
的实现,其中AnnotationMetadata
和MethodMetadata
的获取直接基于Class
(即对应的Class
文件必须存在与类路径)ScannedGenericBeanDefinition
,不同于前者,AnnotationMetadata
和MethodMetadata
的获取直接基于MetadataReader
ConfigurationClassBeanDefinition
,配置类中@Bean
方法会被解析为ConfigurationClassBeanDefinition
示例
public class BeanDefinitionDemo {
@Component("test")
public static class A {
public String name = "default";
public void a() {
System.out.println("init ...");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 1
@Test
public void test() {
GenericBeanDefinition beanDefinition
= new GenericBeanDefinition();
beanDefinition.setBeanClass(A.class);
// init-method 指定
beanDefinition.setInitMethodName("a");
// 属性注入依赖模式
beanDefinition.setPropertyValues(
new MutablePropertyValues()
.add("name", "dd")
);
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext();
// 注册 bd
context.registerBeanDefinition("test", beanDefinition);
// 容器启动时会基于 bd 创建对应的 bean
context.refresh();
A bean = context.getBean(A.class);
System.out.println(bean.name);
}
// 2
@Test
public void test2() {
// 元数据解析
AnnotationMetadata introspect = AnnotationMetadata.introspect(A.class);
// AnnotatedBeanDefinition 会根据传入的元数据解析 beanClass
AnnotatedBeanDefinition beanDefinition
= new AnnotatedGenericBeanDefinition(introspect);
// 注册 bd,beanName 从注解元数据上解析
AnnotationMetadata metadata = beanDefinition.getMetadata();
Map<String, Object> attributes
= metadata.getAnnotationAttributes("org.springframework.stereotype.Component");
String beanName = attributes.get("value").toString();
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext();
context.registerBeanDefinition(beanName, beanDefinition);
// 容器启动时会基于 bd 创建对应的 bean
context.refresh();
A bean = context.getBean("test", A.class);
System.out.println(bean.name);
}
}
结合两端测试示例理解一下 BeanDefinition
GenericBeanDefinition
的使用,指定BeanClass
、InitMethodName
、PropertyValues
等属性,构造对应的bean
实例AnnotatedBeanDefinition
的使用,可以指定AnnotationMetadata
,基于元数据解析相关属性,比如示例中beanName
的解析
总结
本章节是对 BeanDefinition
相关类的一个整体梳理,它是一个 使用价值
大于 实现价值
的类,所以下个章节我想结合 Spring
中具体的应用场景来了解 BeanDefinition
如何使用
参考
【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition…)
版权声明:本文为weixin_42189048原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。