深入剖析 Spring 核心数据结构:BeanDefinition

深入剖析 Spring 核心数据结构:BeanDefinition

林纳斯·托瓦兹(Linus Torvalds)说:“我从心底认为,优秀的程序员与平庸的程序员之间的区别,是在于认为自己的代码重要还是数据结构更加重要。平庸的程序员眼里只有代码,优秀的程序员则关注数据结构及之前的关系。” 也许很多人觉得 Spring 神秘莫测,但是如果了解了它的核心数据结构,很多问题迎刃而解。

Spring 中两个数据结构最核心:① BeanDefinition,用于表示 Bean 的定义;② BeanFactory,用于表示整个 IoC 容器。

在前面文章 Spring Bean 生命周期概述中,介绍了 Spring Bean 的生命周期。不知道大家有没有思考过 Spring 在内部是如何表示一个 Bean 的?本篇文章,就来聊一聊 BeanDefinition

问题

使用 Spring 时,尤其是使用 XML 配置的时候,也许我们会这样的问题:

  1. Bean 怎么表示?

  2. Bean 的依赖怎么表示?

  3. init-method 方法怎么存储?

  4. Bean 的一些属性,比如 lazy-init 等,怎么表示?

  5. Bean 构造函数的参数怎么存储?

  6. …​

Java 也有类似的问题,比如怎么表示一个类?Java 通过反射 API 来解决这个问题:

  1. Class

  2. Method

  3. Field

  4. Constructor

  5. Annotation

但是,为什么 Spring 还要自己定义一套呢?主要原因是 Java 反射 API 不满足 Spring 的需求,比如,它没办法表示哪些类是 SCOPE_SINGLETON,哪些类是 SCOPE_PROTOTYPE

另外,Spring 的 Bean 抽象也并不是完全自定义的,它是基于 Java 反射 API 又增加了自定义功能,其核心 API 就是 BeanDefinition。下面,我们来仔细看一下它的继承体系以及内部核心属性。

继承体系

BeanDefinition 继承体系
Figure 1. BeanDefinition 继承体系
  • AttributeAccessor: 提供对 BeanDefinition 属性操作能力。

  • AttributeAccessorSupport: 使用了 Map 进行属性的存储的。

  • BeanMetadataAttributeAccessor: 代表了一个 Bean 元数据的属性操作。

  • BeanMetadataElement: BeanDefinition 元数据,返回该 Bean 的来源。

  • BeanDefinition: 用来描述 Bean,里面存放 Bean 元数据,比如 Bean 类名、scope、属性、构造函数参数列表、依赖的 Bean、是否是单例类、是否是懒加载等一些列信息。

  • AbstractBeanDefinition: 抽象类统一实现了 BeanDefinition 定义的一部分操作,可以说是定义了 BeanDefinition 很多默认的属性。

  • RootBeanDefinition: 代表一个 XML,Java Config来的 BeanDefinition

  • AnnotatedBeanDefinition: 表示注解类型 BeanDefinition。有两个重要的属性:AnnotationMetadataMethodMetadata 分别表示 BeanDefinition 的注解元信息和方法元信息。实现了此接口的 BeanDefinition 可以获取到注解元数据和方法元数据。

  • ChildBeanDefinition: 可以让子 BeanDefinition 定义拥有从父母那里继承配置的能力。

  • GenericBeanDefinition: 是 Spring 2.5 之后才有的,这个的想法是用来替代 RootBeanDefinition/ChildBeanDefinition,而 RootBeanDefinition/ChildBeanDefinition 可以在 Spring 预加载的时候使用。

  • AnnotatedGenericBeanDefinition: 表示 @Configuration 注解注释的 BeanDefinition 类。是 AnnotatedBeanDefinition 的一个具体实现。传入指定类后,可以获取类中的注解。

  • ScannedGenericBeanDefinition: 表示 @Component@Service@Controller 等注解注释的 Bean 类。是 AnnotatedBeanDefinition 的另一个实现,与 AnnotatedGenericBeanDefinition 不同的是,ScannedGenericBeanDefinition 是通过扫描 class,然后操作 ASM 进行解析的。

核心属性

下面主要介绍一下它的核心内部属性:

  1. Map<String, Object> attributes = new LinkedHashMap<>():配置的属性以及属性值。

  2. Object source:存储 Bean 来源,有时是 XML Element 对象。还可以是其他对象。

  3. Object beanClass:Bean 的类型定义,有时是 Class 类型的对象;有时是类的全限定名,此时就是 String 类型。

  4. abstractFlag = false:默认为 false。如果为 true,则表示不打算实例化该 Bean,仅仅作为其他 Bean 的父 Bean。一般与 parent 一起使用,设置 abstract 的 Bean 定义不需要创建实例,仅仅作为 parent 来进行一些通用的配置,后面的 Bean 通过设置 parent 来获取相应的配置信息,从而达到简化配置的目的。

  5. Boolean lazyInit:是否懒加载。

  6. int autowireMode = AUTOWIRE_NO:注入模式,默认为 AUTOWIRE_NO。一共有五个可选项:

    1. AUTOWIRE_NO — 不自动注入。

    2. AUTOWIRE_BY_NAME — 根据名称自动注入。

    3. AUTOWIRE_BY_TYPE — 根据类型自动注入。

    4. AUTOWIRE_CONSTRUCTOR — 自动根据构造函数注入。

    5. AUTOWIRE_AUTODETECT — 自动检测。

  7. int dependencyCheck = DEPENDENCY_CHECK_NONE:依赖检测。一共有四个可选项:

    1. DEPENDENCY_CHECK_NONE — 不进行依赖检测。

    2. DEPENDENCY_CHECK_OBJECTS — 只检测对象引用。

    3. DEPENDENCY_CHECK_SIMPLE — 只检测简单对象:基础类型、EnumCharSequenceNumberDateTemporalURIURLLocaleClass 以及这些类型的数组对象。

    4. DEPENDENCY_CHECK_ALL — 检测所有依赖。

  8. String[] dependsOn:依赖对象的 Bean 名称。

  9. boolean autowireCandidate = true:声明是否是其他依赖的候选 Bean;只会影响根据类型注入的情况,不会影响根据名称明确指明依赖的情况。

  10. boolean primary = false:是否是首选 Bean,标注了 @Primary 则为 true。当 A 类型的 Bean 需要注入 B 类型的实现类,并且 B 类型的实现类有多个,在按类型将 B 的实现类注入到 A 中时,优先注入该属性为 true 的实现类,当然如果同一个类的实现类有多个 primarytrue,则抛出异常。

  11. Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>()

  12. Supplier<?> instanceSupplier:产生对象的生产者。

  13. boolean nonPublicAccessAllowed = true:是否允许访问非 public 的构造器和方法。

  14. boolean lenientConstructorResolution = true:是否采用宽容模式来解析构造函数。如果是 false,则只要参数类型不匹配就抛出异常。

  15. String factoryBeanName:当 Bean 的创建方式是以工厂进行创建的时候,该方法设置工厂的名称。

  16. String factoryMethodName:工厂创建 Bean 时,设置创建 Bean 的方法名称。

  17. ConstructorArgumentValues constructorArgumentValues:构造函数参数值。

  18. MutablePropertyValues propertyValues: 获取类的属性和属性值的类 PropertyValue

  19. MethodOverrides methodOverrides = new MethodOverrides()

  20. String initMethodName:初始化方法名,对应 init-method 或者 @PostConstruct 标注的方法。

  21. String destroyMethodName:销毁方法名,对应 ` 或 `@PreDestroy 标注的方法。

  22. boolean enforceInitMethod = true:强制初始化方法,默认是 false。如果为 true,而且 initMethodName 为空,则报错。

  23. boolean enforceDestroyMethod = true:强制销毁方法,默认是 false。如果为 true,而且 destroyMethodName 为空,则报错。

  24. boolean synthetic = false:是否是合成的。

  25. int role = BeanDefinition.ROLE_APPLICATION:Bean 角色。可选项有三个:

    1. ROLE_APPLICATION — 为应用程序定义。

    2. ROLE_SUPPORT — 为应用程序定义的比较大的对象。

    3. ROLE_INFRASTRUCTURE — 内部定义的基础 Bean。

  26. String description:Bean 描述。

  27. Resource resource:Bean 的来源 Resource 对象。

  28. AnnotationMetadata metadata: 注解元信息。

  29. MethodMetadata factoryMethodMetadata:方法注解元信息。

BeanDefinition 的代码在 spring-framework/BeanDefinition.java 中。感兴趣,可以自己 clone 下来,把玩把玩。

下一篇文章,D瓜哥重点带大家了解一下 BeanFactory深入剖析 Spring 核心数据结构:BeanFactory