Spring Framework 提供了许多接口,您可以使用这些接口来自定义 豆子。本节将它们分组如下:
生命周期回调
要与容器对 bean 生命周期的 Management 进行交互,您可以实现
Spring 和接口。容器调用前者,而后者则让 bean
在初始化和销毁 bean 时执行某些操作。InitializingBeanDisposableBeanafterPropertiesSet()destroy()
| 
 JSR-250 和注解通常被认为是最好的
在现代 Spring 应用程序中接收生命周期回调的实践。使用这些
annotations 意味着你的 bean 没有耦合到特定于 Spring 的接口。
有关详细信息,请参阅使用  如果您不想使用 JSR-250 注解,但仍希望删除
coupling、consider 和 bean 定义元数据。  | 
在内部, Spring 框架使用 implementation 来处理任何
callback 接口,它可以找到并调用适当的方法。如果您需要自定义
功能或其他生命周期行为 Spring 默认不提供,您可以
实施 YOURSELF。有关更多信息,请参阅容器扩展点。BeanPostProcessorBeanPostProcessor
除了初始化和销毁回调之外, Spring Management 的对象还可以
此外,实现接口,以便这些对象可以参与
启动和关闭过程,由容器自身的生命周期驱动。Lifecycle
生命周期回调接口将在 此部分 中介绍。
初始化回调
该接口允许 bean
在容器在
豆。该接口指定单个方法:org.springframework.beans.factory.InitializingBeanInitializingBean
void afterPropertiesSet() throws Exception;
我们建议您不要使用该接口,因为它
不必要地将代码耦合到 Spring。或者,我们建议使用
@PostConstruct 注解或
指定 POJO 初始化方法。对于基于 XML 的配置元数据,
您可以使用该属性指定具有 void 的方法的名称
no-argument 签名。对于 Java 配置,您可以使用 .请参阅 接收生命周期回调。请考虑以下示例:InitializingBeaninit-methodinitMethod@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。
| 
 请注意,通常会执行 and 初始化方法
在容器的单例创建锁中。仅考虑 bean 实例
已完全初始化,并准备好在从方法返回后发布给其他人。这种单独的初始化方法仅意味着
用于验证配置状态并可能准备一些数据结构
基于给定的配置,但没有进一步的外部 Bean 访问活动。
否则,存在初始化死锁的风险。 对于要触发昂贵的初始化后活动的场景,
例如,异步数据库准备步骤,您的 bean 应该实现或依赖于上下文
refresh 事件:implementation 或
声明其 Comments 等效 。
这些变体出现在所有常规单例初始化之后,因此
在任何单例创建锁之外。 或者,您可以实现接口并与
容器的整体生命周期管理,包括自动启动机制,
销毁前停止步骤,以及可能的停止/重启回调(见下文)。  | 
销毁回调
实现该接口后,可以让
bean 在包含它的容器被销毁时获取回调。该接口指定单个方法:org.springframework.beans.factory.DisposableBeanDisposableBean
void destroy() throws Exception;
我们建议您不要使用回调接口,因为它
不必要地将代码耦合到 Spring。或者,我们建议使用
@PreDestroy 注解或
指定 Bean 定义支持的泛型方法。使用基于 XML 的
configuration 元数据中,您可以使用 .
对于 Java 配置,您可以使用 .请参阅 接收生命周期回调。请考虑以下定义:DisposableBeandestroy-method<bean/>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 还支持销毁方法的推理,检测 public 或 method。这是 Java 配置中方法的默认行为
类并自动匹配或实现,也不会将销毁逻辑耦合到 Spring。closeshutdown@Beanjava.lang.AutoCloseablejava.io.Closeable
对于使用 XML 的 destroy 方法推理,您可以分配属性
元素中,一个特殊值,它指示 Spring 自动将
检测特定 Bean 定义的 Bean 类上的 public 或 method。
您还可以在属性上设置此特殊值
将此行为应用于整个 bean 定义集(请参见默认初始化和销毁方法)。destroy-method<bean>(inferred)closeshutdown(inferred)default-destroy-method<beans> | 
| 
 对于扩展的关闭阶段,您可以实现接口并接收
在调用任何 singleton bean 的 destroy 方法之前提前停止信号。
您还可以实现有时限的 stop 步骤,其中容器
将等待所有此类 stop 处理完成,然后再继续销毁方法。  | 
默认 Initialization 和 Destroy 方法
当您编写不使用
特定于 Spring 的接口和回调接口,您
通常编写名称为 、
等等。理想情况下,此类生命周期回调方法的名称在
一个项目,以便所有开发人员使用相同的方法名称并确保一致性。InitializingBeanDisposableBeaninit()initialize()dispose()
你可以将 Spring 容器配置为“查找”命名初始化和销毁
回调方法名称。这意味着,作为应用程序开发人员,
可以编写您的应用程序类并使用名为
而不必为每个 bean 定义配置一个属性。
Spring IoC 容器在创建 bean 时调用该方法(并根据
使用前面描述的标准生命周期回调协定)。
此功能还对初始化和
destroy 方法回调。init()init-method="init"
假设您的初始化回调方法已命名,并且您的 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>
顶级元素上是否存在该属性
属性使 Spring IoC 容器识别在 Bean 上调用的方法
class 作为初始化方法回调。在创建和组装 bean 时,如果
Bean 类具有这样一个方法,则会在适当的时间调用它。default-init-method<beans/>init
您可以通过使用 top-level 元素上的属性以类似方式(即在 XML 中)配置 destroy 方法回调。default-destroy-method<beans/>
现有 Bean 类已经具有以 Variance 命名的回调方法
使用约定,您可以通过指定(在 XML 中,即)来覆盖默认值
method name 来使用本身的 and 属性。init-methoddestroy-method<bean/>
Spring 容器保证调用配置的初始化回调
紧接着为 bean 提供所有依赖项。因此,初始化
callback 在原始 bean 引用上调用,这意味着 AOP 拦截器等
forth 尚未应用于 Bean。首先完全创建目标 Bean,然后
然后应用 AOP 代理(例如)及其拦截器链。如果目标
bean 和 proxy 是单独定义的,你的代码甚至可以与原始的
target bean,绕过代理。因此,应用
interceptor 添加到该方法中,因为这样做会耦合
将 bean 绑定到其代理或拦截器,并在您的代码
直接与原始目标 Bean 交互。init
组合生命周期机制
从 Spring 2.5 开始,您有三个选项来控制 bean 生命周期行为:
- 
InitializingBean和DisposableBean回调接口 - 
自定义和方法
init()destroy() - 
@PostConstruct和@PreDestroy注释- 
您可以组合这些机制来控制给定的 bean。
 
 - 
 
如果为 Bean 配置了多个生命周期机制,并且每个机制都是
配置了不同的方法名称,则每个配置的方法都会在
在此说明之后列出的顺序。但是,如果为这些生命周期机制中的多个配置了相同的方法名称(例如,对于初始化方法),则
该方法运行一次,如上一节所述。init() | 
为同一 bean 配置了多个生命周期机制,具有不同的 初始化方法的调用方式如下:
- 
注释有
@PostConstruct - 
afterPropertiesSet()由回调接口定义InitializingBean - 
自定义配置的方法
init() 
Destroy 方法的调用顺序相同:
- 
注释有
@PreDestroy - 
destroy()由回调接口定义DisposableBean - 
自定义配置的方法
destroy() 
启动和关闭回调
该接口为任何具有自己的
生命周期要求(例如启动和停止某些后台进程):Lifecycle
public interface Lifecycle {
	void start();
	void stop();
	boolean isRunning();
}
任何 Spring Management 的对象都可以实现该接口。然后,当 本身收到启动和停止信号(例如,对于停止/重启
scenario 的 intent 中),它会将这些调用级联到所有实现
在该上下文中定义。它通过委托给 , 所示
在下面的清单中:LifecycleApplicationContextLifecycleLifecycleProcessor
public interface LifecycleProcessor extends Lifecycle {
	void onRefresh();
	void onClose();
}
请注意,它本身是接口的扩展。它还添加了另外两种方法来响应正在刷新的上下文
并关闭。LifecycleProcessorLifecycle
| 
 请注意,常规接口是普通的
显式启动和停止通知的协定,并不意味着自动启动
在上下文刷新时。用于对自动启动的精细控制和平滑
停止特定 bean(包括 startup 和 stop 阶段),请考虑实现
扩展接口。 另外,请注意,不保证在销毁之前收到停止通知。
在常规关闭时,所有 bean 首先收到停止通知
正在传播常规销毁回调。但是,在
上下文的生命周期或停止刷新尝试时,仅调用 destroy 方法。  | 
启动和关闭调用的顺序可能很重要。如果 “depends-on”
关系存在于任意两个对象之间,则依赖端在其
依赖项,并且它在依赖项之前停止。然而,有时,直接的
依赖项是未知的。您可能只知道特定类型的对象应该启动
在其他类型的对象之前。在这些情况下,接口定义
另一个选项,即在其超级接口 .下面的清单显示了接口的定义:SmartLifecyclegetPhase()PhasedPhased
public interface Phased {
	int getPhase();
}
下面的清单显示了接口的定义:SmartLifecycle
public interface SmartLifecycle extends Lifecycle, Phased {
	boolean isAutoStartup();
	void stop(Runnable callback);
}
开始时,阶段最低的对象首先启动。停止时,
遵循 Reverse Order。因此,实现 和
其方法 returns 将是第一个开始的
也是最后一个停下来的。在频谱的另一端,相位值 表示对象应最后启动并停止
first (可能是因为它依赖于其他进程运行)。在考虑
phase 值,同样重要的是要知道,任何未实现的 “normal” 对象的默认 phase 是 。因此,任何
负相位值表示对象应在这些标准之前开始
组件(并在它们之后停止)。对于任何正相位值,情况正好相反。SmartLifecyclegetPhase()Integer.MIN_VALUEInteger.MAX_VALUELifecycleSmartLifecycle0
定义的 stop 方法接受回调。任何
实现必须在该实现的
shutdown 过程完成。这将在必要时启用异步关闭,因为
接口的默认实现 , 等待对象组的超时值
在每个阶段中调用该回调。默认的每阶段超时为 30 秒。
您可以通过在上下文中定义名为 的 bean 来覆盖默认生命周期处理器实例。如果只想修改超时,
定义以下内容就足够了:SmartLifecyclerun()LifecycleProcessorDefaultLifecycleProcessorlifecycleProcessor
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
	<!-- timeout value in milliseconds -->
	<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
如前所述,该接口为
刷新和关闭上下文。后者驱动关闭
进程,就好像已经被显式调用一样,但它发生在上下文为
关闭。另一方面,'refresh' 回调启用了 bean 的另一个功能。刷新上下文时(在所有对象都已
instantiated 和 initialized),则会调用该回调。此时,
default lifecycle processor 检查每个对象的方法返回的布尔值。如果 ,则该对象为
启动,而不是等待显式调用上下文的 OR
它自己的方法(与上下文刷新不同,上下文启动不会发生
automatically 用于标准上下文实现)。值和任何
“depends-on” 关系确定 Startup Sequence,如前所述。LifecycleProcessorstop()SmartLifecycleSmartLifecycleisAutoStartup()truestart()phase
在非 Web 应用程序中正常关闭 Spring IoC 容器
| 
 本节仅适用于非 Web 应用程序。Spring 基于 Web 的实现已经有代码可以正常关闭
当相关 Web 应用程序关闭时,Spring IoC 容器。  | 
如果你在非 Web 应用程序环境中使用 Spring 的 IoC 容器(对于 例如,在富客户端桌面环境中),使用 JVM 的 JVM 中。这样做可以确保正常关闭,并在 singleton bean 的实例,以便释放所有资源。您仍必须配置 并正确实现这些 destroy 回调。
要注册 shutdown 钩子,请调用
在接口上声明,如下例所示: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 类不必关心
其初始化状态的可见性。常规配置字段不必为
标记,只要它们仅在初始化阶段发生突变,
提供类似于 Even for setter based configuration 的可见性保证
state 的 state 在初始阶段是可变的。如果此类字段在
bean 创建阶段及其随后的初始发布,则每当访问它们时,都需要将它们声明为公共锁或由公共锁保护。volatilefinalvolatile
请注意,在单例 bean 实例中对此类配置状态的并发访问,
例如,对于控制器实例或存储库实例,在
这样从容器端开始的 SAFE 初始发布。这包括在通用单例锁中处理的常见单例实例。FactoryBean
对于销毁回调,配置状态保持线程安全,但任何运行时
初始化和销毁之间累积的状态应保存在线程安全状态
结构(或在简单情况下的字段中)按照常见的 Java 准则。volatile
如上所示的深度集成涉及运行时可变状态,例如
必须声明为 .虽然常见的
生命周期回调遵循一定的顺序,例如,开始回调保证
仅在完全初始化后发生,并且仅在初始启动后停止回调,
销毁前公共停止安排有一个特殊情况:它是 strongly
建议任何此类 bean 中的内部状态也允许立即
destroy 回调,因为这可能发生在非常规
在取消引导后或由另一个 Bean 导致停止超时的情况下关闭。Lifecyclerunnablevolatile
| 
 JSR-250 和注解通常被认为是最好的
在现代 Spring 应用程序中接收生命周期回调的实践。使用这些
annotations 意味着你的 bean 没有耦合到特定于 Spring 的接口。
有关详细信息,请参阅使用  如果您不想使用 JSR-250 注解,但仍希望删除
coupling、consider 和 bean 定义元数据。  | 
| 
 请注意,通常会执行 and 初始化方法
在容器的单例创建锁中。仅考虑 bean 实例
已完全初始化,并准备好在从方法返回后发布给其他人。这种单独的初始化方法仅意味着
用于验证配置状态并可能准备一些数据结构
基于给定的配置,但没有进一步的外部 Bean 访问活动。
否则,存在初始化死锁的风险。 对于要触发昂贵的初始化后活动的场景,
例如,异步数据库准备步骤,您的 bean 应该实现或依赖于上下文
refresh 事件:implementation 或
声明其 Comments 等效 。
这些变体出现在所有常规单例初始化之后,因此
在任何单例创建锁之外。 或者,您可以实现接口并与
容器的整体生命周期管理,包括自动启动机制,
销毁前停止步骤,以及可能的停止/重启回调(见下文)。  | 
对于使用 XML 的 destroy 方法推理,您可以分配属性
元素中,一个特殊值,它指示 Spring 自动将
检测特定 Bean 定义的 Bean 类上的 public 或 method。
您还可以在属性上设置此特殊值
将此行为应用于整个 bean 定义集(请参见默认初始化和销毁方法)。destroy-method<bean>(inferred)closeshutdown(inferred)default-destroy-method<beans> | 
| 
 对于扩展的关闭阶段,您可以实现接口并接收
在调用任何 singleton bean 的 destroy 方法之前提前停止信号。
您还可以实现有时限的 stop 步骤,其中容器
将等待所有此类 stop 处理完成,然后再继续销毁方法。  | 
如果为 Bean 配置了多个生命周期机制,并且每个机制都是
配置了不同的方法名称,则每个配置的方法都会在
在此说明之后列出的顺序。但是,如果为这些生命周期机制中的多个配置了相同的方法名称(例如,对于初始化方法),则
该方法运行一次,如上一节所述。init() | 
| 
 请注意,常规接口是普通的
显式启动和停止通知的协定,并不意味着自动启动
在上下文刷新时。用于对自动启动的精细控制和平滑
停止特定 bean(包括 startup 和 stop 阶段),请考虑实现
扩展接口。 另外,请注意,不保证在销毁之前收到停止通知。
在常规关闭时,所有 bean 首先收到停止通知
正在传播常规销毁回调。但是,在
上下文的生命周期或停止刷新尝试时,仅调用 destroy 方法。  | 
| 
 本节仅适用于非 Web 应用程序。Spring 基于 Web 的实现已经有代码可以正常关闭
当相关 Web 应用程序关闭时,Spring IoC 容器。  | 
ApplicationContextAware和BeanNameAware
当 an 创建实现该接口的对象实例时,将提供该实例
并引用该 .下面的清单显示了定义
的界面中:ApplicationContextorg.springframework.context.ApplicationContextAwareApplicationContextApplicationContextAware
public interface ApplicationContextAware {
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
因此,bean 可以通过编程方式操作创建它们
通过接口或将引用强制转换为已知的
子类(例如 ,它公开了
附加功能)。一种用途是以编程方式检索其他 bean。
有时此功能很有用。但是,一般来说,您应该避免使用它,因为
它将代码耦合到 Spring,并且不遵循 Inversion of Control 风格,
其中,协作者作为属性提供给 bean。的其他方法提供对文件资源的访问、发布应用程序事件、
并访问 .这些附加功能在 ApplicationContext 的附加功能中进行了描述。ApplicationContextApplicationContextConfigurableApplicationContextApplicationContextMessageSource
自动装配是获取对 .传统模式和自动装配模式
(如 Autowiring Collaborators 中所述)可以为构造函数参数或 setter 方法参数提供 type 的依赖项,
分别。为了提高灵活性,包括自动装配字段和
多个参数方法,使用基于注释的自动装配功能。如果这样做,
自动连接到字段、构造函数参数或方法
参数,如果字段、构造函数或
有问题的方法带有注释。有关更多信息,请参阅使用 @Autowired。ApplicationContextconstructorbyTypeApplicationContextApplicationContextApplicationContext@Autowired
当 an 创建实现该接口的类时,该类会附带
对其关联对象定义中定义的名称的引用。以下清单
显示了 BeanNameAware 接口的定义:ApplicationContextorg.springframework.beans.factory.BeanNameAware
public interface BeanNameAware {
	void setBeanName(String name) throws BeansException;
}
该回调在填充普通 bean 属性之后但在
初始化回调,例如 OR 自定义
init-method 的InitializingBean.afterPropertiesSet()
其他接口Aware
除了 and (前面讨论过),
Spring 提供了广泛的回调接口,让 bean 向容器指示
它们需要一定的基础设施依赖性。作为一般规则,该名称表示
dependency 类型。下表总结了最重要的接口:ApplicationContextAwareBeanNameAwareAwareAware
| 名字 | 注入的依赖项 | 解释于... | 
|---|---|---|
  | 
声明。  | 
|
  | 
封闭 的事件发布者 .  | 
|
  | 
用于加载 bean 类的类加载器。  | 
|
  | 
声明。  | 
|
  | 
声明 Bean 的名称。  | 
|
  | 
定义了 weaver,用于在加载时处理类定义。  | 
|
  | 
用于解析消息的配置策略(支持参数化和 国际化)。  | 
|
  | 
Spring JMX 通知发布者。  | 
|
  | 
配置了 loader ,用于对资源的低级访问。  | 
|
  | 
容器运行的当前情况。仅在 web-aware Spring 中有效。  | 
|
  | 
容器运行的当前情况。仅在 web-aware Spring 中有效。  | 
再次注意,使用这些接口会将您的代码绑定到 Spring API,并且不会 遵循 Inversion of Control 样式。因此,我们建议将它们用于基础设施 需要以编程方式访问容器的 bean。
| 名字 | 注入的依赖项 | 解释于... | 
|---|---|---|
  | 
声明。  | 
|
  | 
封闭 的事件发布者 .  | 
|
  | 
用于加载 bean 类的类加载器。  | 
|
  | 
声明。  | 
|
  | 
声明 Bean 的名称。  | 
|
  | 
定义了 weaver,用于在加载时处理类定义。  | 
|
  | 
用于解析消息的配置策略(支持参数化和 国际化)。  | 
|
  | 
Spring JMX 通知发布者。  | 
|
  | 
配置了 loader ,用于对资源的低级访问。  | 
|
  | 
容器运行的当前情况。仅在 web-aware Spring 中有效。  | 
|
  | 
容器运行的当前情况。仅在 web-aware Spring 中有效。  |