此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.4spring-doc.cadn.net.cn

自定义 Bean 的性质

Spring Framework 提供了许多接口,您可以使用这些接口来自定义 豆子。本节将它们分组如下:spring-doc.cadn.net.cn

生命周期回调

要与容器对 bean 生命周期的 Management 进行交互,您可以实现 SpringInitializingBeanDisposableBean接口。容器调用afterPropertiesSet()对于前者和destroy()对于后者,让 bean 在初始化和销毁 bean 时执行某些作。spring-doc.cadn.net.cn

The JSR-250@PostConstruct@PreDestroy注释通常被认为是最好的 在现代 Spring 应用程序中接收生命周期回调的实践。使用这些 注释意味着你的 bean 没有耦合到特定于 Spring 的接口。 有关详细信息,请参阅@PostConstruct@PreDestroy.spring-doc.cadn.net.cn

如果您不想使用 JSR-250 注解,但仍希望删除 耦合,请考虑init-methoddestroy-methodBean 定义元数据。spring-doc.cadn.net.cn

在内部,Spring 框架使用BeanPostProcessorimplementations 来处理任何 callback 接口,它可以找到并调用适当的方法。如果您需要自定义 功能或其他生命周期行为 Spring 默认不提供,您可以 实现BeanPostProcessor你自己。有关更多信息,请参阅容器扩展点spring-doc.cadn.net.cn

除了初始化和销毁回调之外, Spring Management 的对象还可以 此外,实现Lifecycle接口,以便这些对象可以参与 启动和关闭过程,由容器自身的生命周期驱动。spring-doc.cadn.net.cn

生命周期回调接口将在 此部分 中介绍。spring-doc.cadn.net.cn

初始化回调

org.springframework.beans.factory.InitializingBean接口允许 bean 在容器在 豆。这InitializingBeaninterface 指定单个方法:spring-doc.cadn.net.cn

void afterPropertiesSet() throws Exception;

我们建议您不要使用InitializingBean接口,因为它 不必要地将代码耦合到 Spring。或者,我们建议使用 这@PostConstructannotation 或 指定 POJO 初始化方法。对于基于 XML 的配置元数据, 您可以使用init-method属性来指定具有 void 的方法的名称 no-argument 签名。通过 Java 配置,您可以使用initMethod属性@Bean.请参阅 接收生命周期回调。请考虑以下示例:spring-doc.cadn.net.cn

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {

	public void init() {
		// do some initialization work
	}
}
class ExampleBean {

	fun init() {
		// do some initialization work
	}
}

前面的示例与以下示例的效果几乎完全相同 (由两个列表组成):spring-doc.cadn.net.cn

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {

	@Override
	public void afterPropertiesSet() {
		// do some initialization work
	}
}
class AnotherExampleBean : InitializingBean {

	override fun afterPropertiesSet() {
		// do some initialization work
	}
}

但是,前面两个示例中的第一个示例并没有将代码耦合到 Spring。spring-doc.cadn.net.cn

请注意,@PostConstruct和初始化方法通常执行 在容器的单例创建锁中。仅考虑 bean 实例 已完全初始化,并准备好在从@PostConstruct方法。这种单独的初始化方法仅意味着 用于验证配置状态并可能准备一些数据结构 基于给定的配置,但没有进一步的外部 Bean 访问活动。 否则,存在初始化死锁的风险。spring-doc.cadn.net.cn

对于要触发昂贵的初始化后活动的场景, 例如,异步数据库准备步骤,您的 bean 应该实现SmartInitializingSingleton.afterSingletonsInstantiated()或依赖上下文 刷新事件:实现ApplicationListener<ContextRefreshedEvent>或 声明其 annotation 等效项@EventListener(ContextRefreshedEvent.class). 这些变体出现在所有常规单例初始化之后,因此 在任何单例创建锁之外。spring-doc.cadn.net.cn

或者,您可以实现(Smart)Lifecycle接口并集成 容器的整体生命周期管理,包括自动启动机制, 销毁前 Stop 步骤,以及可能的 stop/restart 回调(见下文)。spring-doc.cadn.net.cn

销毁回调

实施org.springframework.beans.factory.DisposableBean接口允许 bean 在包含它的容器被销毁时获取回调。这DisposableBeaninterface 指定单个方法:spring-doc.cadn.net.cn

void destroy() throws Exception;

我们建议您不要使用DisposableBeancallback 接口,因为它 不必要地将代码耦合到 Spring。或者,我们建议使用 这@PreDestroyannotation 或 指定 Bean 定义支持的泛型方法。使用基于 XML 的 configuration 元数据,您可以使用destroy-method属性<bean/>. 通过 Java 配置,您可以使用destroyMethod属性@Bean.请参阅 接收生命周期回调。请考虑以下定义:spring-doc.cadn.net.cn

<bean id="exampleDestructionBean" class="examples.ExampleBean" destroy-method="cleanup"/>
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)
	}
}

前面的定义与下面的定义几乎完全相同:spring-doc.cadn.net.cn

<bean id="exampleDestructionBean" class="examples.AnotherExampleBean"/>
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-doc.cadn.net.cn

请注意, Spring 还支持销毁方法的推理,检测公共closeshutdown方法。这是 的默认行为@BeanJava 配置中的 methods 类并自动匹配java.lang.AutoCloseablejava.io.Closeable实现,也没有将销毁逻辑耦合到 Spring。spring-doc.cadn.net.cn

对于使用 XML 的销毁方法推理,您可以分配destroy-method属性 的<bean>元素为特殊(inferred)值,它指示 Spring 自动 检测公共closeshutdown方法。 您还可以将此(inferred)default-destroy-method属性 的<beans>元素将此行为应用于整个 Bean 定义集(请参见默认初始化和销毁方法)。

对于延长的关闭阶段,您可以实施Lifecycle接口和接收 在调用任何 singleton bean 的 destroy 方法之前提前停止信号。 您还可以实现SmartLifecycle对于有时限的 Stop 步骤,其中容器 将等待所有此类 stop 处理完成,然后再继续销毁方法。spring-doc.cadn.net.cn

默认 Initialization 和 Destroy 方法

当您编写不使用 特定于 SpringInitializingBeanDisposableBean回调接口,则 通常编写名称为init(),initialize(),dispose(), 等等。理想情况下,此类生命周期回调方法的名称在 一个项目,以便所有开发人员使用相同的方法名称并确保一致性。spring-doc.cadn.net.cn

你可以将 Spring 容器配置为“查找”命名初始化和销毁 回调方法名称。这意味着,作为应用程序开发人员, 可以编写您的应用程序类并使用名为init(), 而无需配置init-method="init"属性。 Spring IoC 容器在创建 bean 时调用该方法(并根据 使用前面描述的标准生命周期回调协定)。 此功能还对初始化和 destroy 方法回调。spring-doc.cadn.net.cn

假设您的初始化回调方法被命名为init()还有你的销毁 回调方法被命名为destroy().然后,您的类类似于 以下示例:spring-doc.cadn.net.cn

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 中使用该类:spring-doc.cadn.net.cn

<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在 Bean 上 class 作为初始化方法回调。在创建和组装 bean 时,如果 Bean 类具有这样一个方法,则会在适当的时间调用它。spring-doc.cadn.net.cn

您可以类似地(即在 XML 中)通过使用default-destroy-method属性<beans/>元素。spring-doc.cadn.net.cn

现有 Bean 类已经具有以 Variance 命名的回调方法 使用约定,您可以通过指定(在 XML 中,即)来覆盖默认值 方法名称init-methoddestroy-method的属性<bean/>本身。spring-doc.cadn.net.cn

Spring 容器保证调用配置的初始化回调 紧接着为 bean 提供所有依赖项。因此,初始化 callback 在原始 bean 引用上调用,这意味着 AOP 拦截器等 forth 尚未应用于 Bean。首先完全创建目标 Bean,然后 然后应用 AOP 代理(例如)及其拦截器链。如果目标 bean 和 proxy 是单独定义的,你的代码甚至可以与原始的 target bean,绕过代理。因此,应用 拦截器添加到init方法,因为这样做会耦合 将 bean 绑定到其代理或拦截器,并在您的代码 直接与原始目标 Bean 交互。spring-doc.cadn.net.cn

组合生命周期机制

从 Spring 2.5 开始,您有三个选项来控制 bean 生命周期行为:spring-doc.cadn.net.cn

如果为 Bean 配置了多个生命周期机制,并且每个机制都是 配置了不同的方法名称,则每个配置的方法都会在 在此说明之后列出的顺序。但是,如果配置了相同的方法名称 — 例如,init()对于初始化方法 — 对于这些生命周期机制中的多个, 该方法运行一次,如上一节所述。

为同一 bean 配置了多个生命周期机制,具有不同的 初始化方法的调用方式如下:spring-doc.cadn.net.cn

  1. 注释有@PostConstructspring-doc.cadn.net.cn

  2. afterPropertiesSet()InitializingBean回调接口spring-doc.cadn.net.cn

  3. 自定义配置init()方法spring-doc.cadn.net.cn

Destroy 方法的调用顺序相同:spring-doc.cadn.net.cn

  1. 注释有@PreDestroyspring-doc.cadn.net.cn

  2. destroy()DisposableBean回调接口spring-doc.cadn.net.cn

  3. 自定义配置destroy()方法spring-doc.cadn.net.cn

启动和关闭回调

Lifecycleinterface 为任何具有自己的 生命周期要求(例如启动和停止某些后台进程):spring-doc.cadn.net.cn

public interface Lifecycle {

	void start();

	void stop();

	boolean isRunning();
}

任何 Spring 管理的对象都可以实现Lifecycle接口。然后,当ApplicationContext本身接收开始和停止信号(例如,对于 STOP/RESTART 场景),它会将这些调用级联到所有Lifecycle实现 在该上下文中定义。它通过委托给LifecycleProcessor显示 在下面的清单中:spring-doc.cadn.net.cn

public interface LifecycleProcessor extends Lifecycle {

	void onRefresh();

	void onClose();
}

请注意,LifecycleProcessor本身是Lifecycle接口。它还添加了另外两种方法来响应正在刷新的上下文 并关闭。spring-doc.cadn.net.cn

请注意,常规的org.springframework.context.Lifecycleinterface 是普通的 显式启动和停止通知的协定,并不意味着自动启动 在上下文刷新时。用于对自动启动的精细控制和平滑 停止特定 bean(包括 startup 和 stop 阶段),请考虑实现 扩展的org.springframework.context.SmartLifecycle接口。spring-doc.cadn.net.cn

另外,请注意,不保证在销毁之前收到停止通知。 在常规关闭时,所有Lifecyclebean 首先收到 Stop 通知,然后 正在传播常规销毁回调。但是,在 上下文的生命周期或停止刷新尝试时,仅调用 destroy 方法。spring-doc.cadn.net.cn

启动和关闭调用的顺序可能很重要。如果 “depends-on” 关系存在于任意两个对象之间,则依赖端在其 依赖项,并且它在依赖项之前停止。然而,有时,直接的 依赖项是未知的。您可能只知道特定类型的对象应该启动 在其他类型的对象之前。在这些情况下,SmartLifecycleinterface 定义 另一个选项,即getPhase()方法,即Phased.下面的清单显示了Phased接口:spring-doc.cadn.net.cn

public interface Phased {

	int getPhase();
}

下面的清单显示了SmartLifecycle接口:spring-doc.cadn.net.cn

public interface SmartLifecycle extends Lifecycle, Phased {

	boolean isAutoStartup();

	void stop(Runnable callback);
}

开始时,阶段最低的对象首先启动。停止时, 遵循 Reverse Order。因此,实现SmartLifecycle和 谁的getPhase()method 返回Integer.MIN_VALUE将是第一批开始的人 也是最后一个停下来的。在频谱的另一端,相位值为Integer.MAX_VALUE将指示对象应最后启动并停止 first (可能是因为它依赖于其他进程运行)。在考虑 phase 值,同样重要的是要知道任何 “normal” 的默认 phaseLifecycle未实现SmartLifecycle0.因此,任何 负相位值表示对象应在这些标准之前开始 组件(并在它们之后停止)。对于任何正相位值,情况正好相反。spring-doc.cadn.net.cn

SmartLifecycle接受回调。任何 实现必须调用该回调的run()方法,在该实现的 shutdown 过程完成。这将在必要时启用异步关闭,因为 默认实现的LifecycleProcessor接口DefaultLifecycleProcessor等待对象组的超时值 在每个阶段中调用该回调。默认的每阶段超时为 30 秒。 您可以通过定义一个名为lifecycleProcessor在上下文中。如果只想修改超时, 定义以下内容就足够了:spring-doc.cadn.net.cn

<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
	<!-- timeout value in milliseconds -->
	<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

如前所述,LifecycleProcessorinterface 定义 刷新和关闭上下文。后者驱动关闭 process as ifstop()被显式调用,但当上下文为 关闭。另一方面,'refresh' 回调启用了SmartLifecycle豆。刷新上下文时(在所有对象都已 instantiated 和 initialized),则会调用该回调。此时, 默认生命周期处理器会检查每个SmartLifecycle对象的isAutoStartup()方法。如果true,则该对象为 启动,而不是等待显式调用上下文的 OR 自己start()方法(与上下文刷新不同,上下文启动不会发生 automatically 用于标准上下文实现)。这phasevalue 和任何 “depends-on” 关系确定 Startup Sequence,如前所述。spring-doc.cadn.net.cn

在非 Web 应用程序中正常关闭 Spring IoC 容器

本节仅适用于非 Web 应用程序。Spring 的基于 Web 的ApplicationContext实现已经有代码来正常关闭 当相关 Web 应用程序关闭时,Spring IoC 容器。spring-doc.cadn.net.cn

如果你在非 Web 应用程序环境中使用 Spring 的 IoC 容器(对于 例如,在富客户端桌面环境中),使用 JVM 的 JVM 中。这样做可以确保正常关闭,并在 singleton bean 的实例,以便释放所有资源。您仍必须配置 并正确实现这些 destroy 回调。spring-doc.cadn.net.cn

要注册 shutdown 钩子,请调用registerShutdownHook()方法,即 在ConfigurableApplicationContext接口,如下例所示:spring-doc.cadn.net.cn

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...
}

Thread Safety and Visibility

The Spring core container publishes created singleton instances in a thread-safe manner, guarding access through a singleton lock and guaranteeing visibility in other threads.spring-doc.cadn.net.cn

As a consequence, application-provided bean classes do not have to be concerned about the visibility of their initialization state. Regular configuration fields do not have to be marked as volatile as long as they are only mutated during the initialization phase, providing visibility guarantees similar to final even for setter-based configuration state that is mutable during that initial phase. If such fields get changed after the bean creation phase and its subsequent initial publication, they need to be declared as volatile or guarded by a common lock whenever accessed.spring-doc.cadn.net.cn

Note that concurrent access to such configuration state in singleton bean instances, e.g. for controller instances or repository instances, is perfectly thread-safe after such safe initial publication from the container side. This includes common singleton FactoryBean instances which are processed within the general singleton lock as well.spring-doc.cadn.net.cn

For destruction callbacks, the configuration state remains thread-safe but any runtime state accumulated between initialization and destruction should be kept in thread-safe structures (or in volatile fields for simple cases) as per common Java guidelines.spring-doc.cadn.net.cn

Deeper Lifecycle integration as shown above involves runtime-mutable state such as a runnable field which will have to be declared as volatile. While the common lifecycle callbacks follow a certain order, e.g. a start callback is guaranteed to only happen after full initialization and a stop callback only after an initial start, there is a special case with the common stop before destroy arrangement: It is strongly recommended that the internal state in any such bean also allows for an immediate destroy callback without a preceding stop since this may happen during an extraordinary shutdown after a cancelled bootstrap or in case of a stop timeout caused by another bean.spring-doc.cadn.net.cn

ApplicationContextAware and BeanNameAware

When an ApplicationContext creates an object instance that implements the org.springframework.context.ApplicationContextAware interface, the instance is provided with a reference to that ApplicationContext. The following listing shows the definition of the ApplicationContextAware interface:spring-doc.cadn.net.cn

public interface ApplicationContextAware {

	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

Thus, beans can programmatically manipulate the ApplicationContext that created them, through the ApplicationContext interface or by casting the reference to a known subclass of this interface (such as ConfigurableApplicationContext, which exposes additional functionality). One use would be the programmatic retrieval of other beans. Sometimes this capability is useful. However, in general, you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to beans as properties. Other methods of the ApplicationContext provide access to file resources, publishing application events, and accessing a MessageSource. These additional features are described in Additional Capabilities of the ApplicationContext.spring-doc.cadn.net.cn

Autowiring is another alternative to obtain a reference to the ApplicationContext. The traditional constructor and byType autowiring modes (as described in Autowiring Collaborators) can provide a dependency of type ApplicationContext for a constructor argument or a setter method parameter, respectively. For more flexibility, including the ability to autowire fields and multiple parameter methods, use the annotation-based autowiring features. If you do, the ApplicationContext is autowired into a field, constructor argument, or method parameter that expects the ApplicationContext type if the field, constructor, or method in question carries the @Autowired annotation. For more information, see Using @Autowired.spring-doc.cadn.net.cn

When an ApplicationContext creates a class that implements the org.springframework.beans.factory.BeanNameAware interface, the class is provided with a reference to the name defined in its associated object definition. The following listing shows the definition of the BeanNameAware interface:spring-doc.cadn.net.cn

public interface BeanNameAware {

	void setBeanName(String name) throws BeansException;
}

The callback is invoked after population of normal bean properties but before an initialization callback such as InitializingBean.afterPropertiesSet() or a custom init-method.spring-doc.cadn.net.cn

Other Aware Interfaces

Besides ApplicationContextAware and BeanNameAware (discussed earlier), Spring offers a wide range of Aware callback interfaces that let beans indicate to the container that they require a certain infrastructure dependency. As a general rule, the name indicates the dependency type. The following table summarizes the most important Aware interfaces:spring-doc.cadn.net.cn

Table 1. Aware interfaces
Name Injected Dependency Explained in…​

ApplicationContextAwarespring-doc.cadn.net.cn

Declaring ApplicationContext.spring-doc.cadn.net.cn

ApplicationContextAware and BeanNameAwarespring-doc.cadn.net.cn

ApplicationEventPublisherAwarespring-doc.cadn.net.cn

Event publisher of the enclosing ApplicationContext.spring-doc.cadn.net.cn

Additional Capabilities of the ApplicationContextspring-doc.cadn.net.cn

BeanClassLoaderAwarespring-doc.cadn.net.cn

Class loader used to load the bean classes.spring-doc.cadn.net.cn

Instantiating Beansspring-doc.cadn.net.cn

BeanFactoryAwarespring-doc.cadn.net.cn

Declaring BeanFactory.spring-doc.cadn.net.cn

The BeanFactory APIspring-doc.cadn.net.cn

BeanNameAwarespring-doc.cadn.net.cn

Name of the declaring bean.spring-doc.cadn.net.cn

ApplicationContextAware and BeanNameAwarespring-doc.cadn.net.cn

LoadTimeWeaverAwarespring-doc.cadn.net.cn

Defined weaver for processing class definition at load time.spring-doc.cadn.net.cn

Load-time Weaving with AspectJ in the Spring Frameworkspring-doc.cadn.net.cn

MessageSourceAwarespring-doc.cadn.net.cn

Configured strategy for resolving messages (with support for parameterization and internationalization).spring-doc.cadn.net.cn

Additional Capabilities of the ApplicationContextspring-doc.cadn.net.cn

NotificationPublisherAwarespring-doc.cadn.net.cn

Spring JMX notification publisher.spring-doc.cadn.net.cn

Notificationsspring-doc.cadn.net.cn

ResourceLoaderAwarespring-doc.cadn.net.cn

Configured loader for low-level access to resources.spring-doc.cadn.net.cn

Resourcesspring-doc.cadn.net.cn

ServletConfigAwarespring-doc.cadn.net.cn

Current ServletConfig the container runs in. Valid only in a web-aware Spring ApplicationContext.spring-doc.cadn.net.cn

Spring MVCspring-doc.cadn.net.cn

ServletContextAwarespring-doc.cadn.net.cn

Current ServletContext the container runs in. Valid only in a web-aware Spring ApplicationContext.spring-doc.cadn.net.cn

Spring MVCspring-doc.cadn.net.cn

Note again that using these interfaces ties your code to the Spring API and does not follow the Inversion of Control style. As a result, we recommend them for infrastructure beans that require programmatic access to the container.spring-doc.cadn.net.cn