此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
自定义 Bean 的性质
Spring Framework 提供了许多接口,您可以使用它来自定义性质 豆子的。本节按如下方式对它们进行分组:
生命周期回调
要与容器对 Bean 生命周期的管理进行交互,您可以实现
SpringInitializingBean
和DisposableBean
接口。容器调用afterPropertiesSet()
对于前者和destroy()
让后者让豆子
在初始化和销毁 Bean 时执行某些作。
The JSR-250 如果您不想使用 JSR-250 注释,但仍想删除
耦合,考虑 |
在内部,Spring 框架使用BeanPostProcessor
实现来处理任何
回调接口,它可以找到并调用适当的方法。如果您需要定制
功能或其他生命周期行为 Spring 默认不提供,您可以
实现一个BeanPostProcessor
你自己。有关详细信息,请参阅容器扩展点。
除了初始化和销毁回调之外,Spring 管理的对象还可以
还实现了Lifecycle
接口,以便这些对象可以参与
启动和关闭过程,由容器自身的生命周期驱动。
本节介绍了生命周期回调接口。
初始化回调
这org.springframework.beans.factory.InitializingBean
接口允许 bean
在容器在
豆。这InitializingBean
interface 指定了单个方法:
void afterPropertiesSet() throws Exception;
我们建议您不要使用InitializingBean
接口,因为它
不必要地将代码耦合到 Spring。或者,我们建议使用
这@PostConstruct
注释或
指定 POJO 初始化方法。对于基于 XML 的配置元数据,
您可以使用init-method
属性来指定具有 void 的方法的名称
无参数签名。在 Java 配置中,您可以使用initMethod
属性@Bean
.请参阅接收生命周期回调。请考虑以下示例:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
-
Java
-
Kotlin
public class ExampleBean {
public void init() {
// do some initialization work
}
}
class ExampleBean {
fun init() {
// do some initialization work
}
}
前面的示例与以下示例具有几乎完全相同的效果 (由两个列表组成):
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
-
Java
-
Kotlin
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
class AnotherExampleBean : InitializingBean {
override fun afterPropertiesSet() {
// do some initialization work
}
}
但是,前面两个示例中的第一个示例并未将代码耦合到 Spring。
请注意 对于要触发昂贵的初始化后活动的方案,
例如,异步数据库准备步骤,您的 Bean 应该实现 或者,您可以实现 |
销毁回调
实现org.springframework.beans.factory.DisposableBean
接口允许bean 在包含它的容器被销毁时获得回调。 这DisposableBean
interface 指定了单个方法:
void destroy() throws Exception;
我们建议您不要使用DisposableBean
callback 接口,因为它不必要地将代码耦合到 Spring。或者,我们建议使用 这@PreDestroy
注释或指定 Bean 定义支持的泛型方法。对于基于 XML 的配置元数据,您可以使用destroy-method
属性<bean/>
. 在 Java 配置中,您可以使用destroyMethod
属性@Bean
. 请参阅接收生命周期回调。请考虑以下定义:
<bean id="exampleDestructionBean" class="examples.ExampleBean" destroy-method="cleanup"/>
-
Java
-
Kotlin
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
class ExampleBean {
fun cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
前面的定义与以下定义具有几乎完全相同的效果:
<bean id="exampleDestructionBean" class="examples.AnotherExampleBean"/>
-
Java
-
Kotlin
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
class AnotherExampleBean : DisposableBean {
override fun destroy() {
// do some destruction work (like releasing pooled connections)
}
}
但是,前面两个定义中的第一个不会将代码耦合到 Spring。
请注意,Spring 还支持对 destroy 方法的推断,检测 publicclose
或shutdown
方法。这是@Bean
Java 配置中的方法
类并自动匹配java.lang.AutoCloseable
或java.io.Closeable
实现,也没有将销毁逻辑耦合到 Spring。
对于使用 XML 进行销毁方法推理,您可以分配destroy-method 属性
的<bean> 元素 a 特殊(inferred) value,它指示 Spring 自动
检测公共close 或shutdown 特定 bean 定义的 bean 类上的方法。
您还可以设置此特殊(inferred) 值default-destroy-method 属性
的<beans> 元素将此行为应用于整组 Bean 定义(请参阅默认初始化和销毁方法)。 |
对于延长的关机阶段,您可以实现 |
默认初始化和销毁方法
当您编写初始化和销毁方法回调时,不使用
弹簧专用InitializingBean
和DisposableBean
回调接口,您
通常使用以下名称编写方法init()
,initialize()
,dispose()
,
等等。理想情况下,此类生命周期回调方法的名称在各个领域都是标准化的
一个项目,以便所有开发人员使用相同的方法名称并确保一致性。
您可以将 Spring 容器配置为“查找”命名初始化并销毁
每个 bean 上的回调方法名称。这意味着,作为应用程序开发人员,您,
可以编写应用程序类并使用名为init()
,
无需配置init-method="init"
属性。
Spring IoC 容器在创建 bean 时调用该方法(并根据
与前面描述的标准生命周期回调合约)。
此功能还强制执行一致的初始化命名约定,并且
destroy 方法回调。
假设初始化回调方法名为init()
和你的毁灭
回调方法命名为destroy()
.然后,您的类类似于
以下示例:
-
Java
-
Kotlin
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
class DefaultBlogService : BlogService {
private var blogDao: BlogDao? = null
// this is (unsurprisingly) the initialization callback method
fun init() {
if (blogDao == null) {
throw IllegalStateException("The [blogDao] property must be set.")
}
}
}
然后,您可以在类似于以下内容的 bean 中使用该类:
<beans default-init-method="init">
<bean id="blogService" class="com.something.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>
的存在default-init-method
属性<beans/>
元素
属性导致 Spring IoC 容器识别一个名为init
在豆子上
class 作为初始化方法回调。创建和组装 Bean 时,如果
bean 类有这样的方法,它在适当的时候被调用。
您可以使用default-destroy-method
属性<beans/>
元素。
现有 bean 类已经具有以差异命名的回调方法
使用约定时,您可以通过指定(即在 XML 中)的
方法 name 的init-method
和destroy-method
属性<bean/>
本身。
Spring 容器保证调用配置的初始化回调
立即提供所有依赖项的 bean。因此,初始化
callback 在原始 bean 引用上调用,这意味着 AOP 拦截器等
第四个尚未应用于 bean。首先完全创建目标 Bean,并且
然后应用 AOP 代理(例如)及其拦截器链。如果目标
bean 和代理是单独定义的,你的代码甚至可以与原始
target bean,绕过代理。因此,应用
拦截器到init
方法,因为这样做会耦合
将 bean 定位到其代理或拦截器,并在代码时留下奇怪的语义
直接与原始目标 Bean 交互。
组合生命周期机制
从 Spring 2.5 开始,您有三个选项来控制 Bean 生命周期行为:
-
习惯
init()
和destroy()
方法 -
-
您可以组合这些机制来控制给定的 Bean。
-
如果为 Bean 配置了多个生命周期机制,并且每个机制都是
配置了不同的方法名称,则每个配置的方法都在
在此注释之后列出的顺序。但是,如果配置了相同的方法名称,例如init() 对于初始化方法 — 对于多个生命周期机制,
该方法运行一次,如上一节所述。 |
为同一 Bean 配置的多个生命周期机制,具有不同的 初始化方法,调用如下:
-
用
@PostConstruct
-
afterPropertiesSet()
如InitializingBean
回调接口 -
自定义配置的
init()
方法
Destroy 方法的调用顺序相同:
-
用
@PreDestroy
-
destroy()
如DisposableBean
回调接口 -
自定义配置的
destroy()
方法
启动和关闭回调
这Lifecycle
接口为任何具有自己的对象定义基本方法
生命周期要求(例如启动和停止某些后台进程):
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
任何 Spring 托管的对象都可以实现Lifecycle
接口。然后,当ApplicationContext
本身接收启动和停止信号(例如,对于停止/重新启动
运行时的场景),它会将这些调用级联到Lifecycle
实现
在这种背景下定义。它通过委托给LifecycleProcessor
显示
在以下列表中:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
请注意,LifecycleProcessor
本身就是Lifecycle
接口。它还添加了另外两种方法来对正在刷新的上下文做出反应
并关闭。
请注意,常规 另外,请注意,不能保证在销毁之前会收到停止通知。
在定期关闭时,所有 |
启动和关闭调用的顺序可能很重要。如果“依赖”
关系存在于任意两个对象之间,则依赖端在其之后开始
依赖关系,并且它在依赖关系之前停止。然而,有时,直接
依赖关系未知。您可能只知道某种类型的对象应该启动
在另一种类型的对象之前。在这些情况下,SmartLifecycle
接口定义
另一个选项,即getPhase()
在其超级接口上定义的方法,Phased
.以下列表显示了Phased
接口:
public interface Phased {
int getPhase();
}
以下列表显示了SmartLifecycle
接口:
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
启动时,相位最低的对象首先启动。停止时,
遵循相反的顺序。因此,实现SmartLifecycle
和
谁的getPhase()
方法返回Integer.MIN_VALUE
将是最早开始的
最后一个停下来的。在频谱的另一端,相位值Integer.MAX_VALUE
将指示对象应最后启动并停止
首先(可能是因为它依赖于其他进程的运行)。在考虑
相位值,同样重要的是要知道任何“正常”的默认相位Lifecycle
未实现的对象SmartLifecycle
是0
.因此,任何
负相位值表示对象应在这些标准之前启动
组件(并在它们之后停止)。对于任何正相位值,情况正相关。
由SmartLifecycle
接受回调。任何
实现必须调用该回调的run()
方法,然后是该实现的
关闭过程完成。这在必要时启用异步关闭,因为
默认实现的LifecycleProcessor
接口DefaultLifecycleProcessor
,等待对象组的超时值
在每个阶段中调用该回调。默认的每阶段超时为 30 秒。
您可以通过定义名为lifecycleProcessor
在上下文中。如果只想修改超时,
定义以下内容就足够了:
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
如前所述,LifecycleProcessor
接口定义了
刷新和关闭上下文。后者推动关机
处理好像stop()
已被显式调用,但当上下文为
关闭。另一方面,“refresh”回调启用了另一个功能SmartLifecycle
豆。刷新上下文时(在所有对象都已刷新后)
实例化并初始化),调用该回调。此时,
默认生命周期处理器检查每个SmartLifecycle
对象的isAutoStartup()
方法。如果true
,则该对象是
从那时开始,而不是等待显式调用上下文的 or
自己start()
方法(与上下文刷新不同,上下文启动不会发生
自动用于标准上下文实现)。这phase
value 和任何
“依赖”关系确定启动顺序,如前所述。
在非 Web 应用程序中正常关闭 Spring IoC 容器
本节仅适用于非 Web 应用程序。Spring 的基于 Web 的 |
如果您在非 Web 应用程序环境中使用 Spring 的 IoC 容器(对于 例如,在富客户端桌面环境中),向 JVM.这样做可以确保正常关闭,并在 singleton bean 的 bean,以便释放所有资源。您仍必须配置 并正确实现这些 destroy 回调。
要注册关机挂钩,请调用registerShutdownHook()
方法是
在ConfigurableApplicationContext
接口,如以下示例所示:
-
Java
-
Kotlin
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
}
import org.springframework.context.support.ClassPathXmlApplicationContext
fun main() {
val ctx = ClassPathXmlApplicationContext("beans.xml")
// add a shutdown hook for the above context...
ctx.registerShutdownHook()
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
线程安全性和可见性
Spring 核心容器以线程安全的方式发布创建的单例实例, 通过单例锁保护访问并保证在其他线程中的可见性。
因此,应用程序提供的 bean 类不必担心
其初始化状态的可见性。常规配置字段不必是
标记为volatile
只要它们只是在初始化阶段发生突变,
提供类似于final
甚至对于基于 setter 的配置
在初始阶段可变的状态。如果此类字段在
bean 创建阶段及其随后的初始发布,它们需要声明为volatile
或在访问时由公共锁保护。
请注意,在单例 Bean 实例中并发访问此类配置状态
例如,对于控制器实例或存储库实例,在
从容器端进行如此安全的初始发布。这包括常见的单例FactoryBean
在常规单例锁中处理的实例。
对于销毁回调,配置状态保持线程安全,但任何运行时
初始化和销毁之间累积的状态应保持线程安全
结构(或在volatile
字段)根据常见的 Java 准则。
更深Lifecycle
集成,如上所示涉及运行时可变状态,例如
一个runnable
字段,必须声明为volatile
.虽然常见的
生命周期回调遵循一定的顺序,例如,保证启动回调
仅在完全初始化后发生,并且仅在初始启动后才停止回调,
销毁前的共同停止有一个特殊情况:它很强
建议任何此类 bean 中的内部状态也允许立即
destroy 回调而不预先停止,因为这可能发生在特殊情况下
在取消引导后关闭,或者在另一个 Bean 导致停止超时的情况下关闭。
ApplicationContextAware
和BeanNameAware
当ApplicationContext
创建一个对象实例,该实例实现了org.springframework.context.ApplicationContextAware
接口,则提供实例
并参考了这一点ApplicationContext
.以下列表显示了定义
的ApplicationContextAware
接口:
public interface ApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
因此,bean 可以以编程方式作ApplicationContext
创造了他们,
通过ApplicationContext
接口或通过将引用转换为已知的
该接口的子类(例如ConfigurableApplicationContext
,这会暴露
附加功能)。一种用途是以编程方式检索其他 bean。
有时此功能很有用。但是,一般来说,您应该避免它,因为
它将代码耦合到 Spring,并且不遵循控制反转样式,
其中协作者作为属性提供给 bean。的其他方法ApplicationContext
提供对文件资源的访问、发布应用程序事件、
并访问MessageSource
.这些附加功能在的附加功能ApplicationContext
.
自动布线是获取对ApplicationContext
.传统的 constructor
和byType
自动接线模式
(如自动布线协作器中所述)可以提供类型ApplicationContext
对于构造函数参数或 setter 方法参数,
分别。为了获得更大的灵活性,包括自动布线字段和
多种参数方法,使用基于注释的自动布线功能。如果你这样做,
这ApplicationContext
自动连接到字段、构造函数参数或方法
参数,该参数需要ApplicationContext
如果字段、构造函数或
有问题的方法携带@Autowired
注解。有关更多信息,请参阅用@Autowired
.
当ApplicationContext
创建一个类,实现org.springframework.beans.factory.BeanNameAware
接口,该类提供了
对其关联对象定义中定义的名称的引用。以下列表
显示了 BeanNameAware 接口的定义:
public interface BeanNameAware {
void setBeanName(String name) throws BeansException;
}
回调在普通 bean 属性的填充之后调用,但在
初始化回调,例如InitializingBean.afterPropertiesSet()
或自定义
init-方法。
其他Aware
接口
此外ApplicationContextAware
和BeanNameAware
(前面讨论过),
Spring 提供广泛的Aware
让 bean 向容器指示的回调接口
它们需要一定的基础设施依赖性。作为一般规则,名称表示
依赖类型。下表总结了最重要的Aware
接口:
名称 | 注入的依赖项 | 解释在... |
---|---|---|
|
声明 |
|
|
封闭的事件发布者 |
|
|
用于加载 bean 类的类加载器。 |
|
|
声明 |
|
|
声明 Bean 的名称。 |
|
|
定义了用于在加载时处理类定义的织布器。 |
|
|
配置的消息解析策略(支持参数化和 国际化)。 |
|
|
Spring JMX 通知发布者。 |
|
|
配置了用于对资源的低级访问的加载程序。 |
|
|
当前 |
|
|
当前 |
再次请注意,使用这些接口会将您的代码绑定到 Spring API,而不是 遵循控制反转样式。因此,我们建议将它们用于基础设施 需要以编程方式访问容器的 Bean。