Spring IoC 容器管理一个或多个 bean。这些 bean 是使用配置元数据创建的(例如,以 XML <bean/> 定义的形式)。在容器内,这些 bean 定义表示为 BeanDefinition 对象,其中包含以下元数据:
- 一个包限定的类名:通常是被定义的 bean 的实际实现类。
- Bean 行为配置元素,说明 bean 在容器中的行为(范围、生命周期回调等)。
- 其他 bean 的引用。这些引用也称为协作者或依赖项。
- 其他配置设置 — 例如,池的大小限制或在管理连接池的 bean 中使用的连接数。
此元数据转换为组成每个 bean 定义的一组属性。下表描述了这些属性:
| Property | Explained in… |
|---|---|
| Class | 类名 |
| Name | 命名 |
| Scope | 作用域 |
| Constructor arguments | 构造器注入 |
| Properties | set 方法注入 |
| Autowiring mode | 自动装配 |
| Lazy initialization mode | 懒初始化模式 |
| Initialization method | 初始化 |
| Destruction method | 销毁 |
Bean 的单例实例需要尽早注册,以便容器在自动装配和步骤中正确推理它们。但官方不支持在运行时注册新 bean(与实时访问工厂同时),可能导致并发访问异常或bean 容器中的状态不一致。
命名
每个 bean 都有一个或多个标识符。这些标识符是唯一的,如果需要多个,可以将多余的视为别名。
基于 XML 的配置元数据中,使用 id 属性、name 属性或两者来指定 bean 标识符。 id 属性指定一个 id,通常,这些名称是字母数字(myBean、someService等),也可以包含特殊字符。如果要为 bean 引入其他别名,可以在 name 属性中指定它们,用逗号 (,)、分号 (;) 或空格分隔。
命名约定
命名 bean 时使用标准 Java 约定—以小写字母开头,使用驼峰式大小写。比如 accountManager、accountService、userDao、loginController 等。这样做的ha呕出是使配置更易于阅读和理解。
别名
在 bean 定义中,使用name 属性中任意数量的其他名称,可以为 bean 提供多个名称。
在别处定义的 bean 别名,可以使用<alias/>元素来完成。以下示例显示了如何执行此操作:
1 | <alias name="fromName" alias="toName"/> |
如果使用 Javaconfiguration,则可以使用 @Bean 注解来提供别名。
实例化 bean
bean definition 本质上是创建一个或多个对象的配方。当被请求时,容器会查看该配方,并使用该 bean 定义封装的配置元数据来创建(或获取)实际对象。
基于 XML 的配置元数据,要指定在 <bean/> 元素的 class 属性中实例化的对象的类型(或类)。这个class属性(在内部,它是 BeanDefinition 实例上的 Class 属性)是强制性的。
可以通过以下两种方式之一使用 Class 属性:
- 在容器本身通过反射调用其构造函数直接创建 bean ,等同于带有 new 运算符的 Java 代码。
- 容器调用类上的静态工厂方法来创建 bean。调用静态工厂方法返回的对象类型可能是同一个类,也可能是另一类。
使用构造函数实例化
通过构造函数方法创建 bean ,所有普通类都可以被 Spring 使用并与 Spring 兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 bean class就足够了。根据该 bean 使用的 IoC 类型,可能需要一个默认(空)构造函数。
基于 XML 的配置元数据,可以按如下方式:
1 | <bean id="exampleBean" class="examples.ExampleBean"/> |
使用静态工厂方法实例化
使用实例工厂方法实例化
确定 Bean 的运行时类型
bean 元数据定义中的指定类只是一个初始类引用,可能与声明的工厂方法结合或作为 FactoryBean 类,导致 bean 的不同运行时类型,或者在实例的情况下根本没有设置-level factory 方法(通过指定的 factory-bean 名称解析)。此外,AOP 代理可以使用基于接口的代理包装 bean 实例,并限制暴露目标 bean 的实际类型(仅其实现的接口)。
推荐方法是对指定 bean 名称的 BeanFactory.getType 调用。