的附加功能ApplicationContext

正如本章介绍中所讨论的,该org.springframework.beans.factorypackage 提供了管理和作 bean 的基本功能,包括在 程序化方式。这org.springframework.contextpackage 添加ApplicationContext接口,它扩展了BeanFactory接口,除了扩展其他 接口,以便在更多应用程序中提供附加功能 面向框架的风格。许多人使用ApplicationContext在完全 声明式时尚,甚至不是以编程方式创建它,而是依赖于 支持类,例如ContextLoader自动实例化ApplicationContext作为 Jakarta EE Web 应用程序正常启动过程的一部分。spring-doc.cadn.net.cn

增强BeanFactory功能以更面向框架的风格,上下文 package 还提供以下功能:spring-doc.cadn.net.cn

使用MessageSource

ApplicationContextinterface 扩展了一个名为MessageSource和 因此,提供国际化(“i18n”)功能。Spring 还提供了HierarchicalMessageSource接口,可以分层解析消息。 这些接口共同为 Spring 效果消息提供了基础 分辨率。在这些接口上定义的方法包括:spring-doc.cadn.net.cn

  • String getMessage(String code, Object[] args, String default, Locale loc):基本 用于从MessageSource.找不到消息时 对于指定的区域设置,将使用默认消息。传入的任何参数都会变成 替换值,使用MessageFormat标准提供的功能 图书馆。spring-doc.cadn.net.cn

  • String getMessage(String code, Object[] args, Locale loc):本质上与 与前一种方法相同,但有一个区别:不能指定默认消息。如果 找不到消息,则NoSuchMessageException被抛出。spring-doc.cadn.net.cn

  • String getMessage(MessageSourceResolvable resolvable, Locale locale):所有属性 在前面的方法中使用的也包装在名为MessageSourceResolvable,您可以将其与此方法一起使用。spring-doc.cadn.net.cn

ApplicationContext加载时,它会自动搜索MessageSourcebean 在上下文中定义。豆子必须有名称messageSource.如果这样的豆子 找到,则对上述方法的所有调用都委托给消息源。如果没有 消息源,则ApplicationContext尝试查找包含 同名的豆子。如果是这样,它会使用该 bean 作为MessageSource.如果ApplicationContext找不到消息的任何源,则为空DelegatingMessageSource被实例化,以便能够接受对 上面定义的方法。spring-doc.cadn.net.cn

Spring 提供了三个MessageSource实现ResourceBundleMessageSource,ReloadableResourceBundleMessageSourceStaticMessageSource.他们都实现了HierarchicalMessageSource为了做嵌套 消息。这StaticMessageSource很少使用,但提供了编程方式 将消息添加到源。以下示例显示ResourceBundleMessageSource:spring-doc.cadn.net.cn

<beans>
	<bean id="messageSource"
			class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basenames">
			<list>
				<value>format</value>
				<value>exceptions</value>
				<value>windows</value>
			</list>
		</property>
	</bean>
</beans>

该示例假设您有三个名为format,exceptionswindows在类路径中定义。任何解析消息的请求都是 以 JDK 标准的方式处理消息解析ResourceBundle对象。对于 本示例的目的是,假设上述两个资源包文件的内容 如下:spring-doc.cadn.net.cn

# in format.properties
message=Alligators rock!
# in exceptions.properties
argument.required=The {0} argument is required.

下一个示例显示了一个程序,用于运行MessageSource功能性。 请记住,所有ApplicationContext实现也是MessageSource实现,因此可以转换为MessageSource接口。spring-doc.cadn.net.cn

public static void main(String[] args) {
	MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
	String message = resources.getMessage("message", null, "Default", Locale.ENGLISH);
	System.out.println(message);
}
fun main() {
	val resources = ClassPathXmlApplicationContext("beans.xml")
	val message = resources.getMessage("message", null, "Default", Locale.ENGLISH)
	println(message)
}

上述程序的结果输出如下:spring-doc.cadn.net.cn

Alligators rock!

总而言之,MessageSource在名为beans.xml哪 存在于类路径的根目录中。这messageSourcebean 定义是指 通过其basenames财产。三个文件 将列表中传递给basenames属性作为文件存在于您的根目录下 classpath 并调用format.properties,exceptions.propertieswindows.properties分别。spring-doc.cadn.net.cn

下一个示例显示传递给消息查找的参数。这些论点是 转换为String对象并插入到查找消息中的占位符中。spring-doc.cadn.net.cn

<beans>

	<!-- this MessageSource is being used in a web application -->
	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basename" value="exceptions"/>
	</bean>

	<!-- lets inject the above MessageSource into this POJO -->
	<bean id="example" class="com.something.Example">
		<property name="messages" ref="messageSource"/>
	</bean>

</beans>
public class Example {

	private MessageSource messages;

	public void setMessages(MessageSource messages) {
		this.messages = messages;
	}

	public void execute() {
		String message = this.messages.getMessage("argument.required",
			new Object [] {"userDao"}, "Required", Locale.ENGLISH);
		System.out.println(message);
	}
}
	class Example {

	lateinit var messages: MessageSource

	fun execute() {
		val message = messages.getMessage("argument.required",
				arrayOf("userDao"), "Required", Locale.ENGLISH)
		println(message)
	}
}

调用execute()方法如下:spring-doc.cadn.net.cn

The userDao argument is required.

关于国际化(“i18n”),Spring 的各种MessageSource实现遵循与标准 JDK 相同的区域设置解析和回退规则ResourceBundle.简而言之,继续这个例子messageSource定义 以前,如果您想解决针对英国(en-GB) locale,您 将创建名为format_en_GB.properties,exceptions_en_GB.propertieswindows_en_GB.properties分别。spring-doc.cadn.net.cn

通常,区域设置解析由 应用。在以下示例中,(英国)消息所针对的区域设置 resolved 是手动指定的:spring-doc.cadn.net.cn

# in exceptions_en_GB.properties
argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
public static void main(final String[] args) {
	MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
	String message = resources.getMessage("argument.required",
		new Object [] {"userDao"}, "Required", Locale.UK);
	System.out.println(message);
}
fun main() {
	val resources = ClassPathXmlApplicationContext("beans.xml")
	val message = resources.getMessage("argument.required",
			arrayOf("userDao"), "Required", Locale.UK)
	println(message)
}

运行上述程序的结果输出如下:spring-doc.cadn.net.cn

Ebagum lad, the 'userDao' argument is required, I say, required.

您还可以使用MessageSourceAware接口来获取对任何MessageSource这已经定义了。在ApplicationContext实现MessageSourceAware接口注入了 应用程序上下文的MessageSource创建和配置 Bean 时。spring-doc.cadn.net.cn

因为Spring的MessageSource基于 Java 的ResourceBundle,它不会合并 捆绑包,但仅使用找到的第一个捆绑包。 具有相同基本名称的后续消息包将被忽略。
作为替代方案ResourceBundleMessageSource,Spring 提供了一个ReloadableResourceBundleMessageSource类。此变体支持相同的捆绑包 文件格式,但比基于标准 JDK 的 JDK 更灵活ResourceBundleMessageSource实现。特别是,它允许阅读 来自任何 Spring 资源位置(不仅来自类路径)的文件,并支持热 重新加载捆绑属性文件(同时在两者之间有效地缓存它们)。 请参阅ReloadableResourceBundleMessageSourcejavadoc 了解详情。

标准和自定义事件

事件处理ApplicationContext通过ApplicationEventclass 和ApplicationListener接口。如果实现ApplicationListener接口被部署到上下文中,每次ApplicationEvent发布到ApplicationContext,则通知该 bean。 从本质上讲,这是标准的 Observer 设计模式。spring-doc.cadn.net.cn

从 Spring 4.2 开始,活动基础设施得到了显着改进,并提供了 基于注释的模型以及 能够发布任何任意事件(即不一定 从ApplicationEvent).当这样的对象被发布时,我们将其包装在 为您举办的活动。

下表描述了 Spring 提供的标准事件:spring-doc.cadn.net.cn

表 1.内置事件
事件 解释

ContextRefreshedEventspring-doc.cadn.net.cn

发布时ApplicationContext初始化或刷新(例如,通过 使用refresh()方法ConfigurableApplicationContext接口)。 这里,“初始化”意味着加载所有 bean,检测到后处理器 bean 和 activated,则单例被预先实例化,并且ApplicationContext对象是 准备使用。只要上下文尚未关闭,就可以触发刷新 多次,前提是选择的ApplicationContext其实支持这样的 “热”刷新。例如XmlWebApplicationContext支持热刷新,但GenericApplicationContext不。spring-doc.cadn.net.cn

ContextStartedEventspring-doc.cadn.net.cn

发布时ApplicationContext通过使用start()方法ConfigurableApplicationContext接口。这里,“started”意味着所有Lifecyclebean 接收显式启动信号。通常,此信号用于重新启动 bean 在显式停止后,但它也可用于启动尚未停止的组件 配置为 autostart(例如,尚未启动的组件 初始化)。spring-doc.cadn.net.cn

ContextStoppedEventspring-doc.cadn.net.cn

发布时ApplicationContext通过使用stop()方法ConfigurableApplicationContext接口。这里,“停止”意味着所有Lifecyclebean 接收显式停止信号。停止的上下文可以通过start()叫。spring-doc.cadn.net.cn

ContextClosedEventspring-doc.cadn.net.cn

发布时ApplicationContext正在使用close()方法 在ConfigurableApplicationContext接口或通过 JVM 关闭钩子。这里 “closed”表示所有单例 bean 都将被销毁。关闭上下文后, 它已达到其生命周期,无法刷新或重新启动。spring-doc.cadn.net.cn

RequestHandledEventspring-doc.cadn.net.cn

一个特定于 Web 的事件,告诉所有 Bean HTTP 请求已得到服务。这 请求完成后发布事件。此活动只适用于 使用 Spring 的DispatcherServlet.spring-doc.cadn.net.cn

ServletRequestHandledEventspring-doc.cadn.net.cn

的子类RequestHandledEvent添加特定于 Servlet 的上下文信息。spring-doc.cadn.net.cn

您还可以创建和发布自己的自定义事件。以下示例显示了 简单类,扩展 Spring 的ApplicationEvent基类:spring-doc.cadn.net.cn

public class BlockedListEvent extends ApplicationEvent {

	private final String address;
	private final String content;

	public BlockedListEvent(Object source, String address, String content) {
		super(source);
		this.address = address;
		this.content = content;
	}

	// accessor and other methods...
}
class BlockedListEvent(source: Any,
					val address: String,
					val content: String) : ApplicationEvent(source)

发布自定义ApplicationEvent,调用publishEvent()方法ApplicationEventPublisher.通常,这是通过创建一个实现ApplicationEventPublisherAware并将其注册为 Spring bean。以下内容 示例显示了这样的类:spring-doc.cadn.net.cn

public class EmailService implements ApplicationEventPublisherAware {

	private List<String> blockedList;
	private ApplicationEventPublisher publisher;

	public void setBlockedList(List<String> blockedList) {
		this.blockedList = blockedList;
	}

	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}

	public void sendEmail(String address, String content) {
		if (blockedList.contains(address)) {
			publisher.publishEvent(new BlockedListEvent(this, address, content));
			return;
		}
		// send email...
	}
}
class EmailService : ApplicationEventPublisherAware {

	private lateinit var blockedList: List<String>
	private lateinit var publisher: ApplicationEventPublisher

	fun setBlockedList(blockedList: List<String>) {
		this.blockedList = blockedList
	}

	override fun setApplicationEventPublisher(publisher: ApplicationEventPublisher) {
		this.publisher = publisher
	}

	fun sendEmail(address: String, content: String) {
		if (blockedList!!.contains(address)) {
			publisher!!.publishEvent(BlockedListEvent(this, address, content))
			return
		}
		// send email...
	}
}

在配置时,Spring 容器检测到EmailService实现ApplicationEventPublisherAware并自动调用setApplicationEventPublisher().实际上,传入的参数是 Spring 容器本身。您正在通过应用程序上下文的ApplicationEventPublisher接口。spring-doc.cadn.net.cn

接收自定义ApplicationEvent,您可以创建一个类来实现ApplicationListener并将其注册为 Spring bean。以下示例 显示这样的类:spring-doc.cadn.net.cn

public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {

	private String notificationAddress;

	public void setNotificationAddress(String notificationAddress) {
		this.notificationAddress = notificationAddress;
	}

	public void onApplicationEvent(BlockedListEvent event) {
		// notify appropriate parties via notificationAddress...
	}
}
class BlockedListNotifier : ApplicationListener<BlockedListEvent> {

	lateinit var notificationAddress: String

	override fun onApplicationEvent(event: BlockedListEvent) {
		// notify appropriate parties via notificationAddress...
	}
}

请注意ApplicationListener通常使用自定义事件的类型(BlockedListEvent在前面的示例中)。 这意味着onApplicationEvent()方法可以保持类型安全,避免任何向下转换的需要。 您可以根据需要注册任意数量的事件侦听器,但请注意,默认情况下,事件侦听器会同步接收事件。 这意味着publishEvent()method 块,直到所有侦听器都处理完事件。 这种同步和单线程方法的一个优点是,当侦听器收到事件时, 如果事务上下文可用,则它在发布者的事务上下文中运行。 如果需要其他事件发布策略,例如,缺省情况下的异步事件处理, 请参阅 javadoc 了解 Spring 的ApplicationEventMulticaster接口 和SimpleApplicationEventMulticaster实现 用于可应用于自定义“applicationEventMulticaster”bean 定义的配置选项。 在这些情况下,不会传播 ThreadLocals 和日志记录上下文以进行事件处理。 看@EventListener可观测性部分了解有关可观测性问题的更多信息。spring-doc.cadn.net.cn

以下示例显示了用于注册和配置每个 上述类:spring-doc.cadn.net.cn

<bean id="emailService" class="example.EmailService">
	<property name="blockedList">
		<list>
			<value>[email protected]</value>
			<value>[email protected]</value>
			<value>[email protected]</value>
		</list>
	</property>
</bean>

<bean id="blockedListNotifier" class="example.BlockedListNotifier">
	<property name="notificationAddress" value="[email protected]"/>
</bean>

<!-- optional: a custom ApplicationEventMulticaster definition -->
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
	<property name="taskExecutor" ref="..."/>
	<property name="errorHandler" ref="..."/>
</bean>

将它们放在一起,当sendEmail()方法emailServicebean 是 如果有任何应阻止的电子邮件,则调用 a 自定义事件BlockedListEvent已发布。这blockedListNotifierbean 被注册为ApplicationListener并接收BlockedListEvent,此时它可以 通知有关各方。spring-doc.cadn.net.cn

Spring 的事件机制专为 Spring Bean 之间的简单通信而设计 在同一应用程序上下文中。但是,对于更复杂的企业 集成需求,单独维护的 Spring Integration 项目提供了 完全支持构建轻量级、面向模式、事件驱动的构建 建立在众所周知的 Spring 编程模型之上的架构。

基于注释的事件侦听器

您可以使用@EventListener注解。这BlockedListNotifier可以重写如下:spring-doc.cadn.net.cn

public class BlockedListNotifier {

	private String notificationAddress;

	public void setNotificationAddress(String notificationAddress) {
		this.notificationAddress = notificationAddress;
	}

	@EventListener
	public void processBlockedListEvent(BlockedListEvent event) {
		// notify appropriate parties via notificationAddress...
	}
}
class BlockedListNotifier {

	lateinit var notificationAddress: String

	@EventListener
	fun processBlockedListEvent(event: BlockedListEvent) {
		// notify appropriate parties via notificationAddress...
	}
}
不要将此类 bean 定义为惰性,因为ApplicationContext将尊重这一点,并且不会注册监听事件的方法。

方法签名再次声明它侦听的事件类型, 但是,这一次,使用灵活的名称,并且没有实现特定的监听器接口。 只要实际事件类型,还可以通过泛型缩小事件类型 解析其实现层次结构中的泛型参数。spring-doc.cadn.net.cn

如果你的方法应该监听多个事件,或者如果你想用 参数,也可以在注解本身上指定事件类型。这 以下示例显示了如何执行此作:spring-doc.cadn.net.cn

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
	// ...
}
@EventListener(ContextStartedEvent::class, ContextRefreshedEvent::class)
fun handleContextStart() {
	// ...
}

还可以使用condition属性 定义SpEL表达,应匹配 实际调用特定事件的方法。spring-doc.cadn.net.cn

以下示例显示了如何重写通知程序,仅在content属性等于my-event:spring-doc.cadn.net.cn

@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlockedListEvent(BlockedListEvent blEvent) {
	// notify appropriate parties via notificationAddress...
}
@EventListener(condition = "#blEvent.content == 'my-event'")
fun processBlockedListEvent(blEvent: BlockedListEvent) {
	// notify appropriate parties via notificationAddress...
}

SpELexpression 根据专用上下文进行计算。下表列出了 提供给上下文的项,以便您可以将它们用于条件事件处理:spring-doc.cadn.net.cn

表 2.SpEL 表达式中可用的事件元数据
名称 位置 描述 示例

事件spring-doc.cadn.net.cn

root 对象spring-doc.cadn.net.cn

实际的ApplicationEvent.spring-doc.cadn.net.cn

#root.eventeventspring-doc.cadn.net.cn

参数数组spring-doc.cadn.net.cn

root 对象spring-doc.cadn.net.cn

用于调用该方法的参数(作为对象数组)。spring-doc.cadn.net.cn

#root.argsargs; args[0]访问第一个参数等。spring-doc.cadn.net.cn

参数名称spring-doc.cadn.net.cn

评估背景spring-doc.cadn.net.cn

特定方法参数的名称。如果名称不可用 (例如,因为代码是在没有-parametersflag)、个人 参数也可以使用#a<#arg>语法,其中<#arg>代表 参数索引(从 0 开始)。spring-doc.cadn.net.cn

#blEvent#a0(您也可以使用#p0#p<#arg>参数表示法作为别名)spring-doc.cadn.net.cn

请注意#root.event允许您访问底层事件,即使您的方法signature 实际上引用了已发布的任意对象。spring-doc.cadn.net.cn

如果您需要在处理另一个事件后发布一个事件,您可以更改方法签名以返回应该发布的事件,如以下示例所示:spring-doc.cadn.net.cn

@EventListener
public ListUpdateEvent handleBlockedListEvent(BlockedListEvent event) {
	// notify appropriate parties via notificationAddress and
	// then publish a ListUpdateEvent...
}
@EventListener
fun handleBlockedListEvent(event: BlockedListEvent): ListUpdateEvent {
	// notify appropriate parties via notificationAddress and
	// then publish a ListUpdateEvent...
}
异步侦听器不支持此功能。

handleBlockedListEvent()方法发布一个新的ListUpdateEvent对于每个BlockedListEvent它处理的。如果需要发布多个事件,可以返回 一个Collection或事件数组。spring-doc.cadn.net.cn

异步侦听器

如果您希望特定监听器异步处理事件,您可以重用定期@Async支持. 以下示例显示了如何执行此作:spring-doc.cadn.net.cn

@EventListener
@Async
public void processBlockedListEvent(BlockedListEvent event) {
	// BlockedListEvent is processed in a separate thread
}
@EventListener
@Async
fun processBlockedListEvent(event: BlockedListEvent) {
	// BlockedListEvent is processed in a separate thread
}

使用异步事件时请注意以下限制:spring-doc.cadn.net.cn

对侦听器进行排序

如果您需要在另一个侦听器之前调用一个侦听器,则可以将@OrderComments 添加到方法声明中,如以下示例所示:spring-doc.cadn.net.cn

@EventListener
@Order(42)
public void processBlockedListEvent(BlockedListEvent event) {
	// notify appropriate parties via notificationAddress...
}
@EventListener
@Order(42)
fun processBlockedListEvent(event: BlockedListEvent) {
	// notify appropriate parties via notificationAddress...
}

通用事件

您还可以使用泛型来进一步定义事件的结构。考虑使用EntityCreatedEvent<T>哪里T是创建的实际实体的类型。例如,您 可以创建以下监听器定义以仅接收EntityCreatedEvent对于一个Person:spring-doc.cadn.net.cn

@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
	// ...
}
@EventListener
fun onPersonCreated(event: EntityCreatedEvent<Person>) {
	// ...
}

由于类型擦除,这仅在触发的事件解析泛型 事件侦听器过滤的参数(即,类似于class PersonCreatedEvent extends EntityCreatedEvent<Person> { …​ }).spring-doc.cadn.net.cn

在某些情况下,如果所有事件都遵循相同的内容,这可能会变得非常乏味 结构(与前面示例中的事件一样)。在这种情况下, 您可以实现ResolvableTypeProvider引导框架超越运行时 环境提供。以下事件演示了如何执行此作:spring-doc.cadn.net.cn

public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

	public EntityCreatedEvent(T entity) {
		super(entity);
	}

	@Override
	public ResolvableType getResolvableType() {
		return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
	}
}
class EntityCreatedEvent<T>(entity: T) : ApplicationEvent(entity), ResolvableTypeProvider {

	override fun getResolvableType(): ResolvableType? {
		return ResolvableType.forClassWithGenerics(javaClass, ResolvableType.forInstance(getSource()))
	}
}
这不仅适用于ApplicationEvent但您发送的任何任意对象 一个事件。

最后,和经典一样ApplicationListener实现,实际多播 通过上下文范围发生ApplicationEventMulticaster在运行时。默认情况下,这是一个SimpleApplicationEventMulticaster在调用方线程中发布同步事件。 这可以通过“applicationEventMulticaster”bean 定义来替换/自定义, 例如,异步处理所有事件和/或处理侦听器异常:spring-doc.cadn.net.cn

@Bean
ApplicationEventMulticaster applicationEventMulticaster() {
	SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
	multicaster.setTaskExecutor(...);
	multicaster.setErrorHandler(...);
	return multicaster;
}

方便访问低级资源

为了获得最佳使用和理解应用程序上下文,您应该熟悉自己使用 Spring 的Resource抽象,如参考资料中所述。spring-doc.cadn.net.cn

应用程序上下文是ResourceLoader,可用于加载Resource对象。 一个Resource本质上是 JDK 的功能更丰富的版本java.net.URL类。 事实上,实现Resource包装java.net.URL哪里 适当。 一个Resource可以从几乎任何位置以透明的方式获取低级资源,包括从类路径、文件系统位置、任何地方可以使用标准 URL 进行描述,以及其他一些变体。如果资源位置string 是一个没有任何特殊前缀的简单路径,这些资源的来源是特定且适合实际的应用程序上下文类型。spring-doc.cadn.net.cn

您可以配置部署到应用程序上下文中的 bean 以实现特殊的 回调接口,ResourceLoaderAware,自动回调 初始化时间,应用程序上下文本身作为ResourceLoader. 您还可以公开类型Resource,用于访问静态资源。 它们像任何其他属性一样被注入其中。您可以指定这些Resource属性为简单String路径,并依赖于从这些文本自动转换 字符串到实际Resource对象。spring-doc.cadn.net.cn

提供给ApplicationContext构造函数实际上是 资源字符串,并且以简单的形式根据特定的 上下文实现。例如ClassPathXmlApplicationContext对待简单的 location path 作为类路径位置。您还可以使用位置路径(资源字符串) 使用特殊前缀强制从类路径或 URL 加载定义, 无论实际上下文类型如何。spring-doc.cadn.net.cn

应用程序启动跟踪

ApplicationContext管理 Spring 应用程序的生命周期,并提供丰富的 围绕组件的编程模型。因此,复杂的应用程序可以同样具有 复杂的组件图和启动阶段。spring-doc.cadn.net.cn

使用特定指标跟踪应用程序启动步骤有助于了解在哪里 在启动阶段花费了时间,但它也可以用作更好的一种方式 了解整个上下文生命周期。spring-doc.cadn.net.cn

AbstractApplicationContext(及其子类)使用ApplicationStartup,它收集StartupStep有关各个启动阶段的数据:spring-doc.cadn.net.cn

下面是AnnotationConfigApplicationContext:spring-doc.cadn.net.cn

// create a startup step and start recording
StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan");
// add tagging information to the current step
scanPackages.tag("packages", () -> Arrays.toString(basePackages));
// perform the actual phase we're instrumenting
this.scanner.scan(basePackages);
// end the current step
scanPackages.end();
// create a startup step and start recording
val scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")
// add tagging information to the current step
scanPackages.tag("packages", () -> Arrays.toString(basePackages))
// perform the actual phase we're instrumenting
this.scanner.scan(basePackages)
// end the current step
scanPackages.end()

应用程序上下文已通过多个步骤进行检测。 记录后,可以使用特定工具收集、显示和分析这些启动步骤。 有关现有启动步骤的完整列表,您可以查看专门的附录部分spring-doc.cadn.net.cn

默认值ApplicationStartup实现是一种无作变体,可最大限度地减少开销。 这意味着默认情况下,在应用程序启动期间不会收集任何指标。 Spring Framework 附带了一个用于使用 Java Flight Recorder 跟踪启动步骤的实现:FlightRecorderApplicationStartup.要使用此变体,您必须配置它的实例 到ApplicationContext一旦创建。spring-doc.cadn.net.cn

开发人员还可以使用ApplicationStartup基础设施(如果他们提供自己的)AbstractApplicationContext子类,或者如果他们希望收集更精确的数据。spring-doc.cadn.net.cn

ApplicationStartup仅在应用程序启动期间使用 核心容器;这绝不是 Java 分析器或 像 Micrometer 这样的指标库。

开始收集自定义StartupStep,组件可以获取ApplicationStartup实例直接从应用程序上下文中实现,使其组件实现ApplicationStartupAware, 或要求ApplicationStartup键入任何注射点。spring-doc.cadn.net.cn

开发人员不应使用"spring.*"命名空间。 此命名空间保留供内部 Spring 使用,可能会发生变化。

Web 应用程序的便捷 ApplicationContext 实例化

您可以创建ApplicationContext实例,例如,使用ContextLoader.当然,你也可以创建ApplicationContext实例 以编程方式使用ApplicationContext实现。spring-doc.cadn.net.cn

您可以注册一个ApplicationContext通过使用ContextLoaderListener,作为 以下示例显示:spring-doc.cadn.net.cn

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

监听器检查contextConfigLocation参数。如果参数没有 exist,则监听器使用/WEB-INF/applicationContext.xml作为默认设置。当 参数确实存在,监听器将String通过使用预定义的 分隔符(逗号、分号和空格),并将这些值用作其中的位置 搜索应用程序上下文。还支持 Ant 样式路径模式。 示例包括/WEB-INF/*Context.xml(对于名称以Context.xml并且驻留在WEB-INF目录)和/WEB-INF/**/*Context.xml(对于WEB-INF).spring-doc.cadn.net.cn

部署 SpringApplicationContext作为 Jakarta EE RAR 文件

可以部署 SpringApplicationContext作为 RAR 文件,将 上下文及其在 Jakarta EE RAR 部署中所需的所有 bean 类和库 JAR 单位。这相当于引导一个独立的ApplicationContext(仅托管 在 Jakarta EE 环境中)能够访问 Jakarta EE 服务器设施。RAR 部署 是部署无头 WAR 文件场景的更自然的替代方案——实际上, 一个没有任何 HTTP 入口点的 WAR 文件,仅用于引导 SpringApplicationContext在雅加达 EE 环境中。spring-doc.cadn.net.cn

RAR 部署非常适合不需要 HTTP 入口点但 相反,仅由消息端点和计划作业组成。在这样的上下文中,bean 可以 使用应用程序服务器资源,例如 JTA 事务管理器和 JNDI 绑定的 JDBCDataSource实例和 JMSConnectionFactory实例,也可以注册 平台的 JMX 服务器——全部通过 Spring 的标准事务管理和 JNDI 和 JMX 支持设施。应用程序组件也可以与应用程序交互 服务器的 JCAWorkManager通过 Spring 的TaskExecutor抽象化。spring-doc.cadn.net.cn

请参阅SpringContextResourceAdapterclass 用于 RAR 部署中涉及的配置详细信息。spring-doc.cadn.net.cn

对于将 Spring ApplicationContext 简单部署为 Jakarta EE RAR 文件:spring-doc.cadn.net.cn

  1. 包 所有应用程序类都转换为 RAR 文件(这是一个标准 JAR 文件,具有不同的 文件扩展名)。spring-doc.cadn.net.cn

  2. 将所有必需的库 JAR 添加到 RAR 存档的根目录中。spring-doc.cadn.net.cn

  3. 添加一个META-INF/ra.xml部署描述符(如javadoc 的SpringContextResourceAdapter) 和相应的 Spring XML bean 定义文件(通常META-INF/applicationContext.xml).spring-doc.cadn.net.cn

  4. 将生成的 RAR 文件放入您的 应用程序服务器的部署目录。spring-doc.cadn.net.cn

这种 RAR 部署单元通常是独立的。它们不会暴露组件 对外界,甚至对同一应用程序的其他模块也不行。与 基于 RARApplicationContext通常通过与其共享的 JMS 目标发生 其他模块。基于 RAR 的ApplicationContext例如,还可以安排一些作业 或对文件系统中的新文件(或类似文件)做出反应。如果需要允许同步 从外部访问,它可以(例如)导出 RMI 端点,可以使用 由同一台机器上的其他应用程序模块。