跳到正文
返回

BeanDefinition

发表于 更新于
浏览量: --
系列文章: SpringBoot 源码剖析 7 / 8
  1. 从回调到 LambdaSafe
  2. 获取 ApplicationContext
  3. @Configuration 注解的那些事
  4. SpringBoot 常用拓展点
  5. SpringBoot Shutdown Hook
  6. Spring 的事件监听机制
  7. BeanDefinition 当前文章
  8. Spring 配置类的解析

封面来源:碧蓝航线 特殊背景

0. 前言

7 月中旬介绍了 SpringBoot 中的事件监听机制,一句话概括就是 Spring 环境下观察者模式的实现。在这篇文章中,我曾信誓旦旦地说到要开启「爆肝」模式,原本也是这么计划的,奈何身体抱恙,又去了一趟医院,结果也没检查出个啥,在医生开了几盒药之后留下一句「再观察下」便草草了事。

也不知道身体究竟有没有毛病,感觉在跑了几次医院后,就算没病也焦虑出病了。暂且先不管那么多,保持好心情,拒绝焦虑,拒绝熬夜,做好这几点总归是没有坏处的,后续再找个时间去华西转一圈,如果还是没什么结果,那可能真的是心理作用吧。

如果有朋友恰好看到了我这段文字,希望陌生的你也能保持一个好心情,拒绝焦虑,拒绝熬夜。说到熬夜,网上无论是文字,还是视频,总有无数种方式教年轻人怎么不熬夜,要我说,这些都没用,年轻人真要熬夜,那是拦不住的,只有他自己意识到不该熬夜了,他才不会再熬夜。要说这个意识从何而来,等他叫一次 120 自然就知道了,至少我是这样的。

总之,生命短暂,拒绝熬夜。

言归正传,原计划是在 Spring 的事件监听机制 一文后介绍 SpringBoot 的自动配置机制,但在构思时发现在这之前还需要花点篇幅介绍 @Conditional 注解的使用与实现,然后又发现漏掉了 Spring 中一个很重要的概念 —— BeanDefinition,它是 Spring 管理 Bean 的过程中绕不开的一个类。

为了后续阅读源码时更加得心应手,本文既不介绍 SpringBoot 的自动配置机制,也不介绍 @Conditional 注解的实现,而是剖析 BeanDefinition 体系。

BeanDefinition体系

1. BeanDefinition

BeanDefinition 继承了 AttributeAccessorBeanMetadataElement

一个 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() 方法的注释可知,以下类型被划为「简单」:

注意: Voidvoid 并不「简单」。

public static final int DEPENDENCY_CHECK_ALL = 3;

需要对所有属性进行依赖项检查,相当于是 DEPENDENCY_CHECK_OBJECTSDEPENDENCY_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 将依次判断类中是否存在名为 closeshutdown 的方法,如果存在,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

RootBeanDefinitionAbstractBeanDefinition 的一个实现,它表示 运行时合并的 BeanDefinitionRootBeanDefinition 可以是由多个相互继承的原始 BeanDefinition 创建的。

在 Spring 中,子 BeanDefinition 可以从父 BeanDefinition 中继承属性。RootBeanDefinition 可以用于那些没有父 BeanDefinition BeanDefinition,也可以用于合并父 BeanDefinition 的属性。

RootBeanDefinitionAbstractBeanDefinition 的基础上定义了更多的成员变量。

@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--
}

GenericBeanDefinitionChildBeanDefinition 的实现很类似,也可以通过调用 setParentName() 方法设置父 BeanDefinition 的名称。

尽管两者很类似,但它们表示不同的含义。

除此之外,ChildBeanDefinition 是不能脱离父 BeanDefinition 单独存在的,而 GenericBeanDefinition 可以 按需 设置父 BeanDefinition 的名称。

2.7 区别

GenericBeanDefinition

ChildBeanDefinition

RootBeanDefinition

3. AnnotatedBeanDefinition

AnnotatedBeanDefinitionBeanDefinition 的子接口,能够用来获取注解元数据。一般情况下,通过注解方式得到的 Bean(比如 @Component@Bean),其 BeanDefinition 类型都是该接口的实现类。

public interface AnnotatedBeanDefinition extends BeanDefinition {

    /**
     * 获取当前 BeanDefinition 对应的 Class 的注解元数据(以及基类的元数据)
     */
    AnnotationMetadata getMetadata();

    /**
     * 获取当前 BeanDefinition 的工厂方法元数据,如果有的话
     */
    @Nullable
    MethodMetadata getFactoryMethodMetadata();

}

通过 AnnotationMetadata 能够获取到对应 及其 注解 的元数据信息,这是因为 AnnotationMetadata 又继承了 ClassMetadataAnnotatedTypeMetadata

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
    // --snip--
}

MethodMetadataAnnotationMetadata 类似,能够获取到对应 方法 及其 注解 的元数据信息:

public interface MethodMetadata extends AnnotatedTypeMetadata {
    // --snip--
}

AnnotationMetadataMethodMetadata 提供的 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

ScannedGenericBeanDefinitionAnnotatedGenericBeanDefinition 类似,但它重写 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 信息。

如果这篇文章对你有帮助,可以通过
支付宝
支付宝
微信
微信
请我喝杯 Coffee ☕


上一篇
Spring 配置类的解析
下一篇
Lambda 表达式与函数式编程