前言
创建一个Java Bean,大概是下面这个流程:
我们写的Java文件,会编译为Class文件,运行程序,类加载器会加载Class文件,放入JVM的方法区,我们就可以愉快的new对象了。
创建一个Spring Bean,大概是下面这个流程:
我们写的Java文件,会编译为Class文件,运行程序,类加载器会加载Class文件,放入JVM的方法区,这一步还是保持不变(当然这个也没办法变。。。) 下面就是Spring的事情了,Spring会解析我们的配置类(配置文件),假设现在只配置了A,解析后,Spring会把A的BeanDefinition放到一个map中去,随后,由一个一个的BeanPostProcessor进行加工,最终把经历了完整的Spring生命周期的Bean放入了singleObjects。
BeanDefinition 介绍
借助 IDE ,打开 BeanDefinition
的接口定义,从方法列表上看,BeanDefinition
整体包含以下几个部分:
- Bean 的类信息 - 全限定类名 ( beanClassName )
- Bean 的属性 - 作用域 ( scope ) 、是否默认 Bean ( primary ) 、描述信息 ( description ) 等
- Bean 的行为特征 - 是否延迟加载 ( lazy ) 、是否自动注入 ( autowireCandidate ) 、初始化 / 销毁方法 ( initMethod / destroyMethod ) 等
- Bean 与其他 Bean 的关系 - 父 Bean 名 ( parentName ) 、依赖的 Bean ( dependsOn ) 等
- Bean 的配置属性 - 构造器参数 ( constructorArgumentValues ) 、属性变量值 ( propertyValues ) 等
BeanDefinition
描述了 SpringFramework 中 bean 的元信息,它包含 bean 的类信息、属性、行为、依赖关系、配置信息等。BeanDefinition
具有层次性,并且可以在 IOC 容器初始化阶段被 BeanDefinitionRegistryPostProcessor
构造和注册,被 BeanFactoryPostProcessor
拦截修改等。
两者对比
- BeanDefinition是Spring框架中描述和定义Bean的元数据对象,用于配置和管理Bean的创建和生命周期。
- Class对象是Java反射机制中表示类的元数据对象,用于访问和操作类的静态结构。
- BeanDefinition提供了更高级的抽象和配置能力,而Class对象提供了更底层的操作能力。
- 在Spring容器中,BeanDefinition和Class对象之间存在关联,BeanDefinition使用Class对象来创建和管理Bean的实例。
原因理解1
在Spring框架中,BeanDefinition
有着非常重要的作用。它是Spring对Bean配置的内部表示,包含了需要创建一个Bean的绝大部分信息。BeanDefinition
用于告诉Spring如何创建一个Bean,包括Bean的类型、生命周期、依赖等等。
如果我们只使用Class
来定义Bean,那么我们只能获得Bean的类型信息,无法得知其他信息,比如:
- Bean的作用域(单例、原型等)。
- Bean的构造函数参数或者属性的值,这些值可能来自于其他Bean或者配置文件。
- Bean的初始化方法和销毁方法。
- Bean是否懒加载。
- Bean的别名。
这些信息都是Spring在创建和管理Bean时需要的,而且这些信息都不能通过Class
对象获取,因此Spring定义了BeanDefinition
来保存这些信息。
同时,BeanDefinition
还提供了一种抽象,使得Spring能够支持不同的配置方式,比如XML配置、注解配置,甚至是Groovy配置。所有这些配置最终都会被转换成BeanDefinition
,这让Spring的内部处理变得更加统一和简洁。
所以,BeanDefinition
的设计是非常有必要的,它使得Spring具有了非常强大的灵活性和可扩展性。
原因理解2
在Spring框架中,专门定义BeanDefinition
的目的是为了提供更灵活和可配置的方式来定义和管理Bean的元数据。虽然使用Class
来表示Bean的类型是可能的,但是仅仅使用Class
无法满足一些高级需求和复杂场景。
以下是一些原因和优势,解释为什么要专门定义BeanDefinition
:
-
元数据的扩展性:
BeanDefinition
允许在定义Bean时包含更多的元数据信息,例如Bean的作用域、初始化方法、销毁方法、依赖关系等。这些元数据将会在容器启动时被解析和应用。通过BeanDefinition
,可以提供更多的配置选项和灵活性,以满足不同场景下的需求。 -
多种配置方式:
BeanDefinition
不仅支持使用Class
来定义Bean的类型,还支持其他配置方式,如XML配置、注解配置、Java配置等。这样可以根据具体的需求和喜好选择最适合的配置方式。通过不同的配置方式,可以更灵活地定义和管理Bean。 -
提供统一的Bean定义模型:
BeanDefinition
提供了一个统一的模型来描述Bean的定义,不受具体实现类的限制。它使得不同的配置方式和不同的实现可以共享相同的Bean定义模型,从而实现更好的解耦和可扩展性。 -
支持非实例化Bean:
BeanDefinition
可以表示非实例化的Bean,这些Bean可能是抽象的、接口的或基于工厂方法创建的。使用BeanDefinition
可以描述这些非实例化的Bean,并在需要时进行实例化。 -
提供更多的编程接口和扩展点:Spring框架提供了许多与
BeanDefinition
相关的编程接口和扩展点,例如BeanPostProcessor
、BeanFactoryPostProcessor
等。通过这些接口,可以在Bean的创建和初始化过程中插入自定义逻辑,实现更高级的功能,如AOP、事务管理等。
总之,专门定义BeanDefinition
的目的是为了提供更灵活、可配置和扩展的方式来描述和管理Bean的元数据。它使得Spring框架能够更好地支持不同的配置方式和复杂的应用场景,提供了统一的Bean定义模型和丰富的编程接口。
原因理解3
Spring 定义 BeanDefinition 而不是直接使用 Class 的主要原因有:
- 解耦合
Spring 的 IoC 容器需要管理各种 Bean,如果直接使用 Class,就需要容器直接依赖具体的 Bean Class。定义 BeanDefinition 后,容器只依赖 BeanDefinition,不依赖具体 Class,降低了耦合。
- 提高灵活性
BeanDefinition 中可以定义 Bean 的各种属性,如是否单例、初始化方法、依赖关系等,都可以通过配置灵活控制,不需要修改代码。
- 统一管理
将 Bean 的定义统一提取到配置文件中,便于集中管理。
- 方便扩展
可以基于 BeanDefinition 进行扩展,例如修改其属性、添加其他信息等。
- Bean 实例化提前
由于有了 BeanDefinition,容器初始化时就可以一次性实例化所有的 Bean。如果直接使用 Class,则只有真正使用时才会实例化。
- 避免循环依赖
有了 BeanDefinition 后,容器初始化时实例化 Bean 可以分两步:先实例化,再设置属性。这样可以处理循环依赖。
总之,引入 BeanDefinition 主要是为了实现 IoC 容器的功能,提高灵活性和可扩展性。如果直接使用 Class 会导致容器与 Bean 之间过于紧密的耦合。