此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
Bean 概述
Spring IoC 容器管理一个或多个 bean。这些 bean 是使用
提供给容器的配置元数据(例如,以 XML 的形式<bean/>
定义)。
在容器本身中,这些 bean 定义表示为BeanDefinition
对象,其中包含(除其他信息外)以下元数据:
-
包限定的类名:通常是 bean 正在定义。
-
Bean 行为配置元素,这些元素说明 Bean 在 容器(范围、生命周期回调等)。
-
对 Bean 执行其工作所需的其他 Bean 的引用。这些 引用也称为协作者或依赖项。
-
要在新创建的对象中设置的其他配置设置,例如大小 池的限制或要在管理 连接池。
此元数据转换为构成每个 Bean 定义的一组属性。 下表描述了这些属性:
属性 | 解释在... |
---|---|
类 |
|
名称 |
|
范围 |
|
构造函数参数 |
|
性能 |
|
自动接线模式 |
|
延迟初始化模式 |
|
初始化方法 |
|
销毁方法 |
除了包含有关如何创建特定
bean,则ApplicationContext
实施还允许注册现有的
在容器外部(由用户)创建的对象。这是通过访问
ApplicationContext 的BeanFactory
通过getAutowireCapableBeanFactory()
方法
返回DefaultListableBeanFactory
实现。DefaultListableBeanFactory
通过registerSingleton(..)
和registerBeanDefinition(..)
方法。但是,典型的应用程序仅使用通过常规定义的 Bean
bean 定义元数据。
Bean 元数据和手动提供的单例实例需要尽早注册 尽可能,以便容器在自动布线期间正确推理它们 和其他内省步骤。在覆盖现有元数据和现有 在某种程度上支持单例实例,在 运行时(与对工厂的实时访问同时进行)不受官方支持,并且可能 导致并发访问异常、Bean 容器中的状态不一致或两者兼而有之。 |
覆盖 Bean
当使用 Bean 注册时,会发生 Bean 覆盖,该标识符已是 分配。虽然 bean 覆盖是可能的,但它使配置更难阅读。
Bean 重写将在将来的版本中被弃用。 |
要完全禁用 bean 覆盖,您可以将allowBeanDefinitionOverriding
flag 到false
在ApplicationContext
在刷新之前。在这样的设置中,一个
如果使用 bean 覆盖,则会抛出异常。
默认情况下,容器会记录每次尝试覆盖INFO
水平,以便
您可以相应地调整您的配置。虽然不推荐,但您可以静音
这些日志通过设置allowBeanDefinitionOverriding
flag 到true
.
我们承认在测试场景中重写 bean 很方便,并且从 Spring Framework 6.2 开始,对此有显式支持。有关更多详细信息,请参阅此部分。 |
命名 Bean
每个 bean 都有一个或多个标识符。这些标识符在托管 bean 的容器中必须是唯一的。一个 bean 通常只有一个标识符。但是,如果它需要多个标识符,则额外的可以被视为别名。
在基于 XML 的配置元数据中,您可以使用id
属性,则name
属性或both 来指定 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 的配置元数据可以通过name 的subsystemA-dataSource
. 子系统 B 的配置元数据可以引用a 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
属性BeanDefinition
instance)通常是强制性的。(有关异常,请参阅使用实例工厂方法实例化和 Bean 定义继承。
您可以使用Class
属性,采用以下两种方式之一:
-
通常,要指定在容器 本身通过反射性地调用其构造函数来直接创建 bean,在某种程度上 等效于 Java 代码,其中
new
算子。 -
要指定包含
static
工厂方法,即 调用以创建对象,在不太常见的情况下,容器调用static
factory 方法来创建 bean。返回的对象类型 从static
factory 方法可以是同一类或另一个类 完全上课。
使用构造函数实例化
当您通过构造函数方法创建 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
属性来指定包含static
factory 方法和属性
叫factory-method
以指定工厂方法本身的名称。你应该是
能够调用此方法(使用可选参数,如下所述)并返回
对象,随后将其视为通过构造函数创建的。
这种 bean 定义的一个用法是调用static
工厂。
以下 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-bean
name 代替)。
此外,AOP 代理可能会使用
目标 bean 的实际类型(仅其实现的接口)的公开有限。
了解特定 Bean 的实际运行时类型的推荐方法是
一个BeanFactory.getType
调用指定的 bean 名称。这需要以上所有
cases 考虑并返回对象类型BeanFactory.getBean
call 是
将返回相同的 bean 名称。