|
对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
Bean 概述
Spring IoC 容器管理一个或多个 bean。这些 bean 是使用
提供给容器的配置元数据(例如,以 XML 的形式<bean/>定义)。
在容器本身中,这些 bean 定义表示为BeanDefinition对象,其中包含(除其他信息外)以下元数据:
-
包限定的类名:通常是 bean 正在定义。
-
Bean 行为配置元素,这些元素说明 Bean 在 容器(范围、生命周期回调等)。
-
对 Bean 执行其工作所需的其他 Bean 的引用。这些 引用也称为协作者或依赖项。
-
要在新创建的对象中设置的其他配置设置,例如大小 池的限制或要在管理 连接池。
此元数据转换为构成每个 Bean 定义的一组属性。 下表描述了这些属性:
| 属性 | 解释在... |
|---|---|
类 |
|
名称 |
|
范围 |
|
构造函数参数 |
|
性能 |
|
自动接线模式 |
|
延迟初始化模式 |
|
初始化方法 |
|
销毁方法 |
除了包含有关如何创建特定
bean,则ApplicationContext实施还允许注册现有的
在容器外部(由用户)创建的对象。这是通过访问
ApplicationContext 的BeanFactory通过getBeanFactory()方法,返回
这DefaultListableBeanFactory实现。DefaultListableBeanFactory支持
通过registerSingleton(..)和registerBeanDefinition(..)方法。但是,典型的应用程序仅使用通过常规定义的 Bean
bean 定义元数据。
|
Bean 元数据和手动提供的单例实例需要尽早注册 尽可能,以便容器在自动布线期间正确推理它们 和其他内省步骤。在覆盖现有元数据和现有 在某种程度上支持单例实例,在 运行时(与对工厂的实时访问同时进行)不受官方支持,并且可能 导致并发访问异常、Bean 容器中的状态不一致或两者兼而有之。 |
覆盖 Bean
当使用 Bean 的标识符注册时,会发生 Bean 覆盖 已分配。虽然 bean 覆盖是可能的,但它使配置变得更加困难 阅读,此功能将在将来的版本中弃用。
要完全禁用 bean 覆盖,您可以将allowBeanDefinitionOverridingflag 到false在ApplicationContext在刷新之前。在这样的设置中,一个
如果使用 bean 覆盖,则会抛出异常。
默认情况下,容器记录每个覆盖的 BeanINFO水平,以便您可以
相应地调整您的配置。虽然不建议这样做,但您可以将这些日志静音
通过将allowBeanDefinitionOverridingflag 到true.
命名 Bean
每个 bean 都有一个或多个标识符。这些标识符在 托管 Bean 的容器。一个 bean 通常只有一个标识符。但是,如果它 需要多个,多余的可以被视为别名。
在基于 XML 的配置元数据中,您可以使用id属性,则name属性,或
两者都指定 bean 标识符。这id属性允许您仅指定一个id.
通常,这些名称是字母数字(“myBean”、“someService”等),但它们
也可以包含特殊字符。如果您想为
bean,您也可以在name属性,用逗号 (,),
分号 () 或空格。尽管;id属性定义为xsd:string类型, 豆id唯一性由容器强制执行,但不由 XML 强制执行
解析 器。
您无需提供name或id对于 bean。如果您不提供name或id显式地,容器为该 Bean 生成一个唯一的名称。 然而 如果您想按名称引用该 bean,请使用ref元素或Service Locator 样式查找,则必须提供名称。不提供名称的动机与使用内部 Bean 和自动连接协作器有关。
通过类路径中的组件扫描,Spring 会为未命名的 bean 生成名称
组件,遵循前面描述的规则:本质上,采用简单的类名
并将其初始字符转换为小写。然而,在(不寻常的)特殊
存在多个字符且第一个和第二个字符的情况
是大写的,原始外壳被保留。这些规则与
定义为java.beans.Introspector.decapitalize(Spring 在这里使用)。 |
在 Bean 定义之外对 Bean 进行别名化
在 Bean 定义本身中,您可以使用
最多一个名称的组合,由id属性和任意数量的其他
名称中的name属性。这些名称可以是同一 Bean 的等效别名
并且在某些情况下很有用,例如让应用程序中的每个组件
使用特定于该组件的 Bean 名称来引用公共依赖关系
本身。
指定实际定义 bean 的所有别名并不总是足够的,
然而。有时需要为已定义的 bean 引入别名
别处。这在配置拆分的大型系统中很常见
在每个子系统中,每个子系统都有自己的一组对象定义。
在基于 XML 的配置元数据中,您可以使用<alias/>要完成的元素
这。以下示例显示了如何执行此作:
<alias name="fromName" alias="toName"/>
在这种情况下,名为fromName也可能,
使用此别名定义后,称为toName.
例如,子系统 A 的配置元数据可以通过
名称subsystemA-dataSource.子系统 B 的配置元数据可以引用
一个 DataSource,名称为subsystemB-dataSource.在编写主应用程序时
使用这两个子系统时,主应用程序通过
名称myApp-dataSource.要使所有三个名称都引用同一个对象,您可以
将以下别名定义添加到配置元数据:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
现在,每个组件和主应用程序都可以通过名称引用 dataSource 这是唯一的,并保证不会与任何其他定义发生冲突(实际上 创建命名空间),但它们引用的是同一个 bean。
实例化 Bean
Bean 定义本质上是创建一个或多个对象的配方。这 容器在询问时查看命名 bean 的配方并使用配置 由该 bean 定义封装的元数据,以创建(或获取)实际对象。
如果使用基于 XML 的配置元数据,请指定对象的类型(或类)
即在class属性的<bean/>元素。这class属性(在内部是一个Class属性BeanDefinitioninstance)通常是强制性的。(有关异常,请参阅使用实例工厂方法实例化和 Bean 定义继承。
您可以使用Class属性,采用以下两种方式之一:
-
通常,要指定在容器 本身通过反射性地调用其构造函数来直接创建 bean,在某种程度上 等效于 Java 代码,其中
new算子。 -
要指定包含
static工厂方法,即 调用以创建对象,在不太常见的情况下,容器调用staticfactory 方法来创建 bean。返回的对象类型 从staticfactory 方法可以是同一类或另一个类 完全上课。
使用构造函数实例化
当您通过构造函数方法创建 bean 时,所有普通类都可以通过 和 与 Spring 兼容。也就是说,正在开发的类不需要实现 任何特定接口或以特定方式编码。只需指定 bean 班级应该足够了。但是,根据您为该特定 IoC 使用的类型 bean,您可能需要一个默认(空)构造函数。
Spring IoC 容器几乎可以管理您希望它管理的任何类。是的 不仅限于管理真正的 JavaBeans。大多数 Spring 用户更喜欢实际的 JavaBeans 仅建模默认(无参数)构造函数和适当的 setter 和 getter 在容器中的属性之后。还可以有更异国情调的非豆式 类。例如,如果您需要使用旧连接池 绝对不符合 JavaBean 规范的,Spring 可以将其管理为 井。
使用基于 XML 的配置元数据,您可以按如下方式指定 bean 类:
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
有关向构造函数提供参数的机制的详细信息(如果需要) 以及在构建对象后设置对象实例属性,请参阅注入依赖项。
| 在构造函数参数的情况下,容器可以选择相应的 几个重载构造函数中的构造函数。也就是说,为了避免歧义, 建议使构造函数签名尽可能简单明了。 |
使用静态工厂方法实例化
在定义使用静态工厂方法创建的 bean 时,请使用class属性来指定包含staticfactory 方法和属性 叫factory-method指定工厂方法本身的名称。你应该能够调用此方法(使用可选参数,如下所述)并返回一个实时对象,随后将其视为通过构造函数创建的。这种 bean 定义的一个用途是调用static工厂。
以下 bean 定义指定将通过调用factory 方法来创建 bean。该定义没有指定返回对象的类型(类),而是指定包含工厂方法的类。在此示例中,createInstance()方法必须是static方法。 以下示例演示如何指定工厂方法:
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
以下示例显示了将与前面的 bean 定义一起使用的类:
-
Java
-
Kotlin
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
class ClientService private constructor() {
companion object {
private val clientService = ClientService()
@JvmStatic
fun createInstance() = clientService
}
}
有关向工厂方法提供(可选)参数的机制的详细信息以及在对象从工厂返回后设置对象实例属性,请参阅依赖关系和配置详细信息。
| 在工厂方法参数的情况下,容器可以在多个同名重载方法中选择相应的方法。也就是说,为了避免歧义,建议保持工厂方法签名尽可能简单明了。 |
|
工厂方法重载的一个典型问题案例是 Mockito,它有许多重载
|
使用实例工厂方法实例化
与通过静态工厂方法实例化类似,使用实例工厂方法实例化会调用非静态
方法来创建新 Bean。要使用它
机制,留下class属性为空,并且在factory-bean属性
指定当前(或父级或祖先)容器中包含的 Bean 的名称
要调用以创建对象的实例方法。设置
factory 方法本身与factory-method属性。以下示例显示
如何配置这样的 bean:
<!-- the factory bean, which contains a method called createClientServiceInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
以下示例显示了相应的类:
-
Java
-
Kotlin
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
}
一个工厂类还可以保存多个工厂方法,如以下示例所示:
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
以下示例显示了相应的类:
-
Java
-
Kotlin
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
private val accountService = AccountServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
fun createAccountServiceInstance(): AccountService {
return accountService
}
}
这种方法表明,工厂 Bean 本身可以通过以下方式进行管理和配置 依赖注入 (DI)。 请参阅依赖项和配置的详细信息。
在 Spring 文档中,“工厂 bean”是指在
Spring 容器,它通过实例或静态工厂方法创建对象。相比之下,FactoryBean(注意大写)指的是特定于 Spring 的FactoryBean实现类。 |
确定 Bean 的运行时类型
确定特定 Bean 的运行时类型并非易事。中的指定类
Bean 元数据定义只是一个初始类引用,可能会组合在一起
使用声明的工厂方法或作为FactoryBean类,这可能导致
Bean 的不同运行时类型,或者在实例级别的情况下根本没有设置
factory 方法(通过指定的factory-beanname 代替)。
此外,AOP 代理可能会使用
目标 bean 的实际类型(仅其实现的接口)的公开有限。
了解特定 Bean 的实际运行时类型的推荐方法是
一个BeanFactory.getType调用指定的 bean 名称。这需要以上所有
cases 考虑并返回对象类型BeanFactory.getBeancall 是
将返回相同的 bean 名称。