--- title: Spring Bean date: 2021-12-10 19:15:42 order: 01 categories: - Java - 框架 - Spring - Spring核心 tags: - Java - 框架 - Spring - Bean - BeanDefinition permalink: /pages/90bed6fd/ --- # Spring Bean 在 Spring 中,构成应用程序主体由 Spring IoC 容器管理的对象称为 Bean。**Bean 是由 Spring IoC 容器实例化、装配和管理的对象**。 Bean 以及它们之间的依赖关系反映在容器使用的配置元数据中。 ## Spring Bean 定义 ### BeanDefinition Spring IoC 容器本身,并不能识别配置的元数据。为此,要将这些配置信息转为 Spring 能识别的格式——`BeanDefinition` 对象。 **`BeanDefinition` 是 Spring 中定义 Bean 的配置元信息接口**,它包含: - Bean 类名 - Bean 行为配置元素,如:作用域、自动绑定的模式、生命周期回调等 - 其他 Bean 引用,也可称为合作者(Collaborators)或依赖(Dependencies) - 配置设置,如 Bean 属性(Properties) #### BeanDefinition 元信息 `BeanDefinition` 元信息如下: | 属性(Property) | 说明 | | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | [Class](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-class) | 全类名,必须是具体类,不能用抽象类或接口 | | [Name](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-beanname) | Bean 的名称或者 ID | | [Scope](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes) | Bean 的作用域(如:`singleton`、`prototype` 等) | | [Constructor arguments](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-collaborators) | Bean 构造器参数(用于依赖注入) | | [Properties](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-collaborators) | Bean 属性设置(用于依赖注入) | | [Autowiring mode](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-autowire) | Bean 自动绑定模式(如:通过名称 byName) | | [Lazy initialization mode](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-lazy-init) | Bean 延迟初始化模式(延迟和非延迟) | | [Initialization method](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-lifecycle-initializingbean) | Bean 初始化回调方法名称 | | [Destruction method](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-lifecycle-disposablebean) | Bean 销毁回调方法名称 | #### BeanDefinition 构建 BeanDefinition 构建方式: - 通过 `BeanDefinitionBuilder` - 通过 `AbstractBeanDefinition` 以及派生类 > 💻 Spring Bean 定义示例源码:[BeanDefinitionTests](https://github.com/dunwu/spring-tutorial/blob/master/codes/core/spring-core-ioc/src/test/java/io/github/dunwu/spring/core/bean/BeanDefinitionTests.java) ### Spring Bean 命名 #### Spring Bean 命名规则 每个 Bean 拥有一个或多个标识符(identifiers),这些标识符在 Bean 所在的容器必须是唯一的。通常,一个 Bean 仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来扩充。 在基于 XML 的配置元信息中,开发人员**可以使用 `id` 属性、`name` 属性或来指定 Bean 标识符**。通常,Bean 的标识符由字母组成,允许出现特殊字符。如果要想引入 Bean 的别名的话,可在 `name` 属性使用半角逗号(“,”)或分号(“;”) 来间隔。 Spring 中,**为 Bean 指定 `id` 和 `name` 属性不是必须的**。如果不指定,Spring 会自动为 Bean 分配一个唯一的名称。尽管 Bean 的命名没有限制,不过**官方建议采用驼峰命名法来命名 Bean**。 #### Spring Bean 命名生成器 Spring 提供了两种 Spring Bean 命名生成器: - `DefaultBeanNameGenerator`:默认通用 `BeanNameGenerator` 实现。 - `AnnotationBeanNameGenerator`:基于注解扫描的 `BeanNameGenerator` 实现。 ```java public interface BeanNameGenerator { String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry); } ``` #### Spring Bean 别名 Spring 支持通过 `` 属性为 Bean 设置别名。 Bean 别名(Alias)的作用: - 复用现有的 `BeanDefinition` - 更具有场景化的命名方法,比如: - `` - `` ```xml ``` ## Spring Bean 生命周期 ![](https://raw.githubusercontent.com/dunwu/images/master/snap/20211201102734.png) 1. Spring 对 Bean 进行实例化(相当于 new XXX()) 2. Spring 将值和引用注入到 Bean 对应的属性中 3. 如果 Bean 实现了 `BeanNameAware` 接口,Spring 将 Bean 的 ID 传递给 `setBeanName` 方法 - 作用是通过 Bean 的引用来获得 Bean ID,一般业务中是很少有用到 Bean 的 ID 的 4. 如果 Bean 实现了 `BeanFactoryAware` 接口,Spring 将调用 `setBeanDactory` 方法,并把 `BeanFactory` 容器实例作为参数传入。 - 作用是获取 Spring 容器,如 Bean 通过 Spring 容器发布事件等 5. 如果 Bean 实现了 `ApplicationContextAware` 接口,Spring 容器将调用 `setApplicationContext` 方法,把应用上下文作为参数传入 - 作用与 `BeanFactory` 类似都是为了获取 Spring 容器,不同的是 Spring 容器在调用 `setApplicationContext` 方法时会把它自己作为 `setApplicationContext` 的参数传入,而 Spring 容器在调用 `setBeanFactory` 前需要使用者自己指定(注入)`setBeanFactory` 里的参数 `BeanFactory` 6. 如果 Bean 实现了 `BeanPostProcess` 接口,Spring 将调用 `postProcessBeforeInitialization` 方法 - 作用是在 Bean 实例创建成功后对其进行增强处理,如对 Bean 进行修改,增加某个功能 7. 如果 Bean 实现了 `InitializingBean` 接口,Spring 将调用 `afterPropertiesSet` 方法,作用与在配置文件中对 Bean 使用 `init-method` 声明初始化的作用一样,都是在 Bean 的全部属性设置成功后执行的初始化方法。 8. 如果 Bean 实现了 `BeanPostProcess` 接口,Spring 将调用 `postProcessAfterInitialization` 方法 - `postProcessBeforeInitialization` 是在 Bean 初始化前执行的,而 `postProcessAfterInitialization` 是在 Bean 初始化后执行的 9. 经过以上的工作后,Bean 将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁 10. 如果 Bean 实现了 `DispostbleBean` 接口,Spring 将调用它的 `destory` 方法,作用与在配置文件中对 Bean 使用 `destory-method` 属性的作用一样,都是在 Bean 实例销毁前执行的方法。 ## Spring Bean 注册 注册 Spring Bean 实际上是将 `BeanDefinition` 注册到 IoC 容器中。 ### XML 配置元信息 Spring 的传统配置方式。在 `` 标签中配置元数据内容。 缺点是当 JavaBean 过多时,产生的配置文件足以让你眼花缭乱。 ### 注解配置元信息 使用 `@Bean`、`@Component`、`@Import` 注解注册 Spring Bean。 ### Java API 配置元信息 - 命名方式:`BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)` - 非命名方式:`BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeanDefinitionRegistry)` - 配置类方式:`AnnotatedBeanDefinitionReader#register(Class...)` > 💻 Spring Bean 注册示例源码:[BeanRegistryTests](https://github.com/dunwu/spring-tutorial/blob/master/codes/core/spring-core-ioc/src/test/java/io/github/dunwu/spring/core/bean/BeanRegistryTests.java) ## Spring Bean 实例化 Spring Bean 实例化方式: - 常规方式 - 通过构造器(配置元信息:XML、Java 注解和 Java API) - 通过静态方法(配置元信息:XML、Java 注解和 Java API) - 通过 Bean 工厂方法(配置元信息:XML、Java 注解和 Java API) - 通过 `FactoryBean`(配置元信息:XML、Java 注解和 Java API) - 特殊方式 - 通过 `ServiceLoaderFactoryBean`(配置元信息:XML、Java 注解和 Java API ) - 通过 `AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)` - 通过 `BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)` > 💻 Spring Bean 实例化示例源码:[BeanInstantiationTests](https://github.com/dunwu/spring-tutorial/blob/master/codes/core/spring-core-ioc/src/test/java/io/github/dunwu/spring/core/bean/BeanInstantiationTests.java)、[BeanInstantiationSpecialTests](https://github.com/dunwu/spring-tutorial/blob/master/codes/core/spring-core-ioc/src/test/java/io/github/dunwu/spring/core/bean/BeanInstantiationSpecialTests.java) ## Spring Bean 初始化和销毁 Spring Bean 初始化和销毁的方式有以下几种: 1. 使用 `@PostConstruct` 和 `@PreDestroy` 注解分别指定相应的初始化方法和销毁方法。 2. 实现 `InitializingBean` 接口的 `afterPropertiesSet()` 方法来编写初始化方法;实现 `DisposableBean` 接口的 `destroy()` 方法来编写销毁方法。 - `InitializingBean` 接口包含一个 `afterPropertiesSet` 方法,可以通过实现该接口,然后在这个方法中编写初始化逻辑。 - `DisposableBean`接口包含一个 `destory` 方法,可以通过实现该接口,然后在这个方法中编写销毁逻辑。 3. 自定义初始化方法 - XML 配置:`` - Java 注解:`@Bean(initMethod = "init", destroyMethod = "destroy")` - Java API:`AbstractBeanDefinition#setInitMethodName(String)` 和 `AbstractBeanDefinition#setDestroyMethodName(String)` 分别定义初始化和销毁方法 注意:如果同时存在,执行顺序会按照序列执行。 Bean 的延迟初始化 - xml 方式:`` - 注解方式:`@Lazy` Spring 提供了一个 `BeanPostProcessor` 接口,提供了两个方法 `postProcessBeforeInitialization` 和 `postProcessAfterInitialization`。其中`postProcessBeforeInitialization` 在组件的初始化方法调用之前执行,`postProcessAfterInitialization` 在组件的初始化方法调用之后执行。它们都包含两个入参: - `bean`:当前组件对象; - `beanName`:当前组件在容器中的名称。 > 💻 Spring Bean 初始化和销毁示例源码:[BeanInitDestroyTests](https://github.com/dunwu/spring-tutorial/blob/master/codes/core/spring-core-ioc/src/test/java/io/github/dunwu/spring/core/bean/BeanInitDestroyTests.java) ## Spring Bean 垃圾回收 Spring Bean 垃圾回收步骤: 1. 关闭 Spring 容器(应用上下文) 2. 执行 GC 3. Spring Bean 覆盖的 `finalize()` 方法被回调 ## Spring Bean 作用范围 | Scope | Description | | :---------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [singleton](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes-singleton) | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. | | [prototype](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes-prototype) | Scopes a single bean definition to any number of object instances. | | [request](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes-request) | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring `ApplicationContext`. | | [session](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes-session) | Scopes a single bean definition to the lifecycle of an HTTP `Session`. Only valid in the context of a web-aware Spring `ApplicationContext`. | | [application](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes-application) | Scopes a single bean definition to the lifecycle of a `ServletContext`. Only valid in the context of a web-aware Spring `ApplicationContext`. | | [websocket](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#websocket-stomp-websocket-scope) | Scopes a single bean definition to the lifecycle of a `WebSocket`. Only valid in the context of a web-aware Spring `ApplicationContext`. | ## 参考资料 - [Spring 官方文档之 Core Technologies](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans) - [《小马哥讲 Spring 核心编程思想》](https://time.geekbang.org/course/intro/265)