封面来源:碧蓝航线 特殊背景
0. 前言
7 月中旬介绍了 SpringBoot 中的事件监听机制,一句话概括就是 Spring 环境下观察者模式的实现。在这篇文章中,我曾信誓旦旦地说到要开启「爆肝」模式,原本也是这么计划的,奈何身体抱恙,又去了一趟医院,结果也没检查出个啥,在医生开了几盒药之后留下一句「再观察下」便草草了事。
也不知道身体究竟有没有毛病,感觉在跑了几次医院后,就算没病也焦虑出病了。暂且先不管那么多,保持好心情,拒绝焦虑,拒绝熬夜,做好这几点总归是没有坏处的,后续再找个时间去华西转一圈,如果还是没什么结果,那可能真的是心理作用吧。
如果有朋友恰好看到了我这段文字,希望陌生的你也能保持一个好心情,拒绝焦虑,拒绝熬夜。说到熬夜,网上无论是文字,还是视频,总有无数种方式教年轻人怎么不熬夜,要我说,这些都没用,年轻人真要熬夜,那是拦不住的,只有他自己意识到不该熬夜了,他才不会再熬夜。要说这个意识从何而来,等他叫一次 120 自然就知道了,至少我是这样的。
总之,生命短暂,拒绝熬夜。
言归正传,原计划是在 Spring 的事件监听机制 一文后介绍 SpringBoot 的自动配置机制,但在构思时发现在这之前还需要花点篇幅介绍 @Conditional 注解的使用与实现,然后又发现漏掉了 Spring 中一个很重要的概念 —— BeanDefinition,它是 Spring 管理 Bean 的过程中绕不开的一个类。
为了后续阅读源码时更加得心应手,本文既不介绍 SpringBoot 的自动配置机制,也不介绍 @Conditional 注解的实现,而是剖析 BeanDefinition 体系。

1. BeanDefinition
BeanDefinition 继承了 AttributeAccessor 和 BeanMetadataElement:
AttributeAccessor:提供了对 属性 的操作,表明BeanDefinition能够操作属性BeanMetadataElement:用于获取 Bean 的配置源对象,比如 XML 中的某个元素、注解等。在 Spring 中,常用于调试、诊断和报告错误,不必过于关心这个接口
一个 BeanDefinition 能够描述一个 Bean 实例,包括属性值、构造器参数值、以及具体实现提供的其他信息。它是一个最小化的接口:其主要目的是允许 BeanFactoryPostProcessor 内省和修改属性值及其他 bean 元数据。
内省,introspection,运行时检查对象(包括类、接口、字段和方法)的一种能力,而不需要了解对象的具体实现。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
/**
* Bean 的作用域,单例
*/
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
/**
* Bean 的作用域,多例
*/
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
/**
* 描述 Bean 的角色:应用程序级别的 Bean,通常对应用户自定义的 Bean。
*/
int ROLE_APPLICATION = 0;
/**
* 描述 Bean 的角色:用于支持应用程序基础设施的 Bean,通常由 Spring 或第三方库定义。
*/
int ROLE_SUPPORT = 1;
/**
* 描述 Bean 的角色:完全内部使用的基础设施 Bean,通常由 Spring 框架定义,用于实现内部功能。
*/
int ROLE_INFRASTRUCTURE = 2;
// Modifiable attributes
/**
* 设置当前 BeanDefinition 的父 BeanDefinition,如果有的话。
*/
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
/**
* 指定当前 BeanDefinition 对应的 Bean 的 className
*/
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
/**
* 覆盖并重新制定当前 Bean 的作用域
*/
void setScope(@Nullable String scope);
@Nullable
String getScope();
/**
* 设置当前 Bean 是否需要被懒加载
*/
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,如果有的话。这是调用指定工厂方法的 Bean 的名称。
*/
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
/**
* 指定创建 Bean 对象使用的工厂方法,如果有的话
*/
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
/**
* 返回当前 Bean 的构造器参数值
*/
ConstructorArgumentValues getConstructorArgumentValues();
/**
* 判断当前 Bean 的是否有定义的构造器参数值
*/
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
/**
* 返回应用到 Bean 实例的属性值,返回的 MutablePropertyValues 对象可以在后置处理 BeanFactory 时被修改
*/
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
/**
* 设置初始化方法的名称
*/
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
/**
* 设置销毁方法的名称
*/
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
/**
* 设置当前 BeanDefinition 的角色
*
* @see #ROLE_APPLICATION
* @see #ROLE_SUPPORT
* @see #ROLE_INFRASTRUCTURE
*/
void setRole(int role);
int getRole();
/**
* 设置当前 BeanDefinition 可读的描述
*/
void setDescription(@Nullable String description);
@Nullable
String getDescription();
// Read-only attributes
/**
* 获取当前 BeanDefinition 对应的 ResolvableType
*/
ResolvableType getResolvableType();
/**
* 判断当前 Bean 是否是单例
*/
boolean isSingleton();
/**
* 判断当前 Bean 是否是多例(原型)
*/
boolean isPrototype();
/**
* 判断当前 Bean 是否是“abstract”,如果是,意味着不会被实例化
*/
boolean isAbstract();
/**
* 返回当前 BeanDefinition 来自的资源的描述。
* 以便在出现错误时显示上下文。
*/
@Nullable
String getResourceDescription();
/**
* 获取原始的 BeanDefinition,如果没有,返回 null。
* 这在处理 Bean 的继承和合并时很有用,比如使用父子 BeanDefinition 时,子可以继承父的属性、配置。
* 调用子 BeanDefinition 的 getOriginatingBeanDefinition() 方法时可以拿到父 BeanDefinition。
*/
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
2. AbstractBeanDefinition
AbstractBeanDefinition 是 BeanDefinition 的一个抽象子类,BeanDefinition 的其他实现类都会继承 AbstractBeanDefinition。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// --snip--
}
2.1 内部常量
AbstractBeanDefinition 内部定义了许多常量,这些常量大多与自动装配(注意自动装配和自动配置的区别)有关。
作用域
public static final String SCOPE_DEFAULT = "";
默认 scope 值,等价于 singleton。
自动装配
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
设置自动装配模式时使用,即调用 setAutowireMode() 方法时使用。当前模式表示不需要自动装配,需要手动注入。
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
同上。当前模式表示按照 Bean 的 name 进行自动装配。
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
同上。当前模式表示按照 Bean 的类型进行自动装配。
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
同上。当前模式表示按照构造器参数类型进行自动装配,和 byType 很类似。
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
同上。这是一种在 Spring 3.0 中被标记为废弃的模式,在这种模式下将先按照构造器进行自动装配,如果失败,再尝试通过 byType 的方式进行自动装配。
从注释中得知,如果想要使用混合的自动装配策略,应该使用基于注解的自动装配,以便更清楚地明确自动装配的需求。
依赖检查
public static final int DEPENDENCY_CHECK_NONE = 0;
没有依赖项,无需检查。
public static final int DEPENDENCY_CHECK_OBJECTS = 1;
需要进行对象间引用的检查。
public static final int DEPENDENCY_CHECK_SIMPLE = 2;
需要进行「简单」属性的依赖检查。
可以通过 BeanUtils#isSimpleValueType() 方法来判断哪种类型是「简单」类型,在 Spring 6.1 中,该方法被委派给 ClassUtils.isSimpleValueType() 实现,后续可能会将更多类型纳入「简单」。
暂时根据 BeanUtils#isSimpleValueType() 方法的注释可知,以下类型被划为「简单」:
- 基本类型及其包装类型
- 枚举
- 字符串,即
String、CharSequence - 数字
Number - 时间,即
Date、Temporal - 其他类型,包括
UUID、URI、URL、Locale和Class
注意: Void 和 void 并不「简单」。
public static final int DEPENDENCY_CHECK_ALL = 3;
需要对所有属性进行依赖项检查,相当于是 DEPENDENCY_CHECK_OBJECTS 和 DEPENDENCY_CHECK_SIMPLE 的融合模式。
其他常量
public static final String PREFERRED_CONSTRUCTORS_ATTRIBUTE = "preferredConstructors";
Spring 6.1 中新增的常量,它是一个 BeanDefinition 的属性名(attribute name),以便 BeanDefinition 能够指定一个或多个首选构造器。这类似于 Bean 对应的类中被 @Autowired 标记的构造器。
该属性名对应的属性值可以是一个 Constructor 对象,也可以是其数组。
public static final String ORDER_ATTRIBUTE = "order";
Spring 6.1 中新增的常量,它是一个 BeanDefinition 的属性名(attribute name),以便 BeanDefinition 能够指定目标 Bean 的排序顺序。这类似于 @Order 注解。
public static final String INFER_METHOD = "(inferred)";
Bean 的销毁方法的推断值。以 @Bean 注解为例,其 destroyMethod 属性的默认值就是该值,如果未显式设置该值,在 Bean 的销毁期间,Spring 会尝试推断对应类中的销毁方法。
目前,Spring 将依次判断类中是否存在名为 close 和 shutdown 的方法,如果存在,Spring 将认定它们为未显式指定的销毁方法,并在销毁期间执行那个方法。
2.2 成员变量
相比于常量,AbstractBeanDefinition 内部定义了更多的成员变量,这些成员变量也体现了 Bean 的特性。
@Nullable
private volatile Object beanClass;
Bean 对应的 Class 对象。
@Nullable
private String scope = SCOPE_DEFAULT;
Bean 的作用域。
private boolean abstractFlag = false;
是否是抽象。
@Nullable
private Boolean lazyInit;
是否懒加载,或者说延迟加载。
private int autowireMode = AUTOWIRE_NO;
自动装配模式,默认不自动装配。
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
依赖检查,默认没有依赖。
@Nullable
private String[] dependsOn;
依赖列表。
private boolean autowireCandidate = true;
是否是自动装配时的候选值,默认是。
private boolean primary = false;
是否是首选。
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
存放的 Qualifier 信息,以便自动装配时确定被装配的 Bean。与 @Qualifier 和 @Autowired 注解有关。
@Nullable
private Supplier<?> instanceSupplier;
获取 Bean 实例。
private boolean nonPublicAccessAllowed = true;
是否允许访问非 public 的构造器。
private boolean lenientConstructorResolution = true;
是否以宽松模式来解析构造器。如果存在多个候选的构造器,在严格模式下,会抛出异常;而在宽松模式下,Spring 会选择最合适的构造器进行注入,以免抛出异常,这提升了 Spring 的灵活性和容错能力。
@Nullable
private String factoryBeanName;
构造当前 BeanDefinition 的工厂 Bean 的名称。
@Nullable
private String factoryMethodName;
构造当前 BeanDefinition 的工厂方法名称。
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
构造器的参数值,这些值也是注入的属性值。
@Nullable
private MutablePropertyValues propertyValues;
注入的属性值。
private MethodOverrides methodOverrides = new MethodOverrides();
管理和存储与方法重载的相关信息,在处理 Bean 中的方法替换和方法注入时有用。
方法替换,Method Replacer,使用 ReplaceOverride 类表示方法替换。允许在运行时替换 Bean 中的方法实现,而不需要修改原始类的代码。
方法注入,Lookup Method Injection,使用 LookupOverride 类表示方法注入。允许在运行时注入一个新的 Bean 实例到方法中,而不需要修改原始类的代码。
@Nullable
private String[] initMethodNames;
初始化方法。
@Nullable
private String[] destroyMethodNames;
销毁方法。
private boolean enforceInitMethod = true;
是否强制执行初始化方法。
private boolean enforceDestroyMethod = true;
是否强制执行销毁方法。
private boolean synthetic = false;
当前 BeanDefinition 是否是「合成的」(synthetic),所谓「合成的」,就是由框架内部生成的,而不是用户自定义的。比如 AOP 中生成的代理 BeanDefinition 就是由 Spring 自动生成的,会被标记为「合成的」。
private int role = BeanDefinition.ROLE_APPLICATION;
Bean 的角色,默认为应用程序级别。
@Nullable
private String description;
Bean 的描述信息。
@Nullable
private Resource resource;
当前 BeanDefinition 来自的资源(Resource)。
2.3 构造器与方法
AbstractBeanDefinition 中的构造器都比较简单,没有什么特殊逻辑,就不再赘述。
AbstractBeanDefinition 中的方法大多数操作成员变量的 Getter、Setter,没啥营养,也略过。
2.4 RootBeanDefinition
RootBeanDefinition 是 AbstractBeanDefinition 的一个实现,它表示 运行时合并的 BeanDefinition。RootBeanDefinition 可以是由多个相互继承的原始 BeanDefinition 创建的。
在 Spring 中,子 BeanDefinition 可以从父 BeanDefinition 中继承属性。RootBeanDefinition 可以用于那些没有父 BeanDefinition 的 根 BeanDefinition,也可以用于合并父 BeanDefinition 的属性。
RootBeanDefinition 在 AbstractBeanDefinition 的基础上定义了更多的成员变量。
@Nullable
private BeanDefinitionHolder decoratedDefinition;
存储了 Bean 的名称、别名、BeanDefinition。三个愿望,一次满足!🥪
@Nullable
private AnnotatedElement qualifiedElement;
AnnotatedElement 由 JDK 提供,通过该成员变量能够查看 Bean 的注解信息。
volatile boolean stale;
确定是否需要重新合并当前 BeanDefinition。
boolean allowCaching = true;
是否允许缓存。
boolean isFactoryMethodUnique;
工厂方法是否唯一。
@Nullable
volatile ResolvableType targetType;
当前 BeanDefinition 对应的 ResolvableType。
ResolvableType 的使用可以参考 Spring 的事件监听机制 的第一节。
@Nullable
volatile Class<?> resolvedTargetType;
缓存给定 BeanDefinition 对应的 Class 信息。
@Nullable
volatile Boolean isFactoryBean;
缓存当前 Bean 是否是工厂 Bean。
@Nullable
volatile ResolvableType factoryMethodReturnType;
缓存工厂方法的返回值类型。
@Nullable
volatile Method factoryMethodToIntrospect;
缓存唯一的工厂方法候选值。
@Nullable
volatile String resolvedDestroyMethodName;
缓存销毁方法的名称(包括推断出的销毁方法名称)。
// 以下四个构造器字段的通用锁
final Object constructorArgumentLock = new Object();
// 缓存已解析的构造器或工厂方法。
// Executable 由 JDK 提供,是 Method 和 Constructor 的公共基类。
@Nullable
Executable resolvedConstructorOrFactoryMethod;
// 标记构造器参数全都被解析。
boolean constructorArgumentsResolved = false;
//缓存已经解析的构造器参数。
@Nullable
Object[] resolvedConstructorArguments;
// 缓存部分准备好的构造器参数(待解析的构造器参数)。
@Nullable
Object[] preparedConstructorArguments;
// 以下两个后处理字段的公共锁
final Object postProcessingLock = new Object();
// 是否已经被 MergedBeanDefinitionPostProcessor 处理过。
boolean postProcessed = false;
// 实例化前的后处理器是否已启动。这在生成代理时会使用,表示是否已经生成了代理。
@Nullable
volatile Boolean beforeInstantiationResolved;
@Nullable
private Set<Member> externallyManagedConfigMembers;
保存由外部管理的配置成员(成员变量、成员方法)。
@Nullable
private Set<String> externallyManagedInitMethods;
保存由外部管理的初始化方法,比如被 @PostConstruct 注解标记的方法。
@Nullable
private Set<String> externallyManagedDestroyMethods;
保存由外部管理的销毁方法,比如被 @PreDestroy 注解标记的方法。
2.5 ChildBeanDefinition
ChildBeanDefinition 也是 AbstractBeanDefinition 的一种实现,它表示继承了父 BeanDefinition 相关设置的一种 BeanDefinition。子 BeanDefinition 对父 BeanDefinition 具有固定的依赖关系。
子 BeanDefinition 可以从父 BeanDefinition 继承构造器参数值、属性值和 methodOverrides 信息,同时也可以添加新的值。子 BeanDefinition 可以覆盖父 BeanDefinition 的初始化方法、销毁方法和静态工厂方法。其余剩下的设置将始终从子 BeanDefinition 中获取,比如依赖关系、自动装配模式、依赖检查、是否单例、是否懒加载。
从 Spring 2.5 开始,通过编程方式注册 BeanDefinition 时,更推荐的方式是使用 GenericBeanDefinition,通过调用其 setParentName() 方法能够动态地定义父子依赖关系。这实际上取代了大多数使用场景中的 ChildBeanDefinition 类。
ChildBeanDefinition 的实现比较简单,仅有一个 String 类型的成员变量 parentName:
public class ChildBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
// --snip--
}
通过构造 ChildBeanDefinition 时传入 parentName,或者调用 setParentName() 方法设置 parentName,能够指定对应父 BeanDefinition 的名称。
2.6 GenericBeanDefinition
GenericBeanDefinition 是 Spring 2.5 引入了的 BeanDefinition,它能够很好地替代 ChildBeanDefinition。
public class GenericBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
// --snip--
}
GenericBeanDefinition 和 ChildBeanDefinition 的实现很类似,也可以通过调用 setParentName() 方法设置父 BeanDefinition 的名称。
尽管两者很类似,但它们表示不同的含义。
除此之外,ChildBeanDefinition 是不能脱离父 BeanDefinition 单独存在的,而 GenericBeanDefinition 可以 按需 设置父 BeanDefinition 的名称。
2.7 区别
GenericBeanDefinition:
- 一个 通用的
BeanDefinition,适用于大多数场景
ChildBeanDefinition:
- 一个 继承于 其他
BeanDefinition的BeanDefinition,不能脱离父BeanDefinition - 常在 XML 配置文件中使用
- 自 Spring 2.5 之后,它逐渐被
GenericBeanDefinition取代
RootBeanDefinition:
- 一个 顶级
BeanDefinition,没有父BeanDefinition的BeanDefinition: - 包含完整
BeanDefinition的信息,不依赖于其他 Bean
3. AnnotatedBeanDefinition
AnnotatedBeanDefinition 是 BeanDefinition 的子接口,能够用来获取注解元数据。一般情况下,通过注解方式得到的 Bean(比如 @Component、@Bean),其 BeanDefinition 类型都是该接口的实现类。
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* 获取当前 BeanDefinition 对应的 Class 的注解元数据(以及基类的元数据)
*/
AnnotationMetadata getMetadata();
/**
* 获取当前 BeanDefinition 的工厂方法元数据,如果有的话
*/
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
通过 AnnotationMetadata 能够获取到对应 类 及其 注解 的元数据信息,这是因为 AnnotationMetadata 又继承了 ClassMetadata 和 AnnotatedTypeMetadata:
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
// --snip--
}
MethodMetadata 和 AnnotationMetadata 类似,能够获取到对应 方法 及其 注解 的元数据信息:
public interface MethodMetadata extends AnnotatedTypeMetadata {
// --snip--
}
AnnotationMetadata 与 MethodMetadata 提供的 API 都比较简单、清晰,这里不再讲解它们的用法。
4. 其他实现
4.1 AnnotatedGenericBeanDefinition
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;
// --snip--
}
AnnotatedGenericBeanDefinition 继承 GenericBeanDefinition 还实现了 AnnotatedBeanDefinition,该类用来描述通过注解获取到的 BeanDefinition。
AnnotatedGenericBeanDefinition 重写了 getFactoryMethodMetadata() 方法:
@Override
@Nullable
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
表示该 BeanDefinition 是可以由工厂方法创建。
使用了 @Configuration 注解标记的配置类会解析为 AnnotatedGenericBeanDefinition。
4.2 ScannedGenericBeanDefinition
ScannedGenericBeanDefinition 和 AnnotatedGenericBeanDefinition 类似,但它重写 getFactoryMethodMetadata() 方法直接返回了 null:
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
// --snip--
@Override
@Nullable
public MethodMetadata getFactoryMethodMetadata() {
return null;
}
}
通过包扫描自动注册的 Bean 会被解析为 ScannedGenericBeanDefinition,比如被 @Component 及其派生注解标记的类。
4.3 ConfigurationClassBeanDefinition
ConfigurationClassBeanDefinition 是位于 ConfigurationClassBeanDefinitionReader 类中的一个静态嵌套类:
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
// --snip--
}
在被 @Configuration 注解标记的配置类中,通过 @Bean 注解定义的 Bean 会被解析成 ConfigurationClassBeanDefinition。
继承 RootBeanDefinition 也表示 @Bean 注解定义的 Bean 是一个顶级 Bean,已经包含了全部 BeanDefinition 信息。