如章节介绍中所述,该包提供了用于管理和操作 bean 的基本功能,包括
编程方式。该包添加了 ApplicationContext 接口,该接口除了扩展了其他
接口,以便在更多应用程序中提供额外的功能
面向框架的样式。许多人完全使用
声明式方式,甚至不是以编程方式创建它,而是依赖于
支持类,例如在 Jakarta EE Web 应用程序的正常启动过程中自动实例化 an。org.springframework.beans.factoryorg.springframework.contextBeanFactoryApplicationContextContextLoaderApplicationContext
为了以更面向框架的样式增强功能,上下文
package 还提供以下功能:BeanFactory
- 
通过界面访问 i18n 风格的消息。
MessageSource - 
通过界面访问资源,例如 URL 和文件。
ResourceLoader - 
事件发布,即向实现接口 通过使用界面。
ApplicationListenerApplicationEventPublisher - 
加载多个 (分层) 上下文,让每个上下文都专注于一个 特定层,例如应用程序的 Web 层,通过接口。
HierarchicalBeanFactory 
国际化使用MessageSource
该接口扩展了一个名为 and 的接口。
因此,提供国际化 (“i18n”) 功能。Spring 还提供了接口,该接口可以分层解析消息。
这些接口共同为 Spring effects 消息提供了基础
分辨率。在这些接口上定义的方法包括:ApplicationContextMessageSourceHierarchicalMessageSource
- 
String getMessage(String code, Object[] args, String default, Locale loc): 基本 用于从 .未找到消息时 对于指定的区域设置,将使用 default message。传入的任何参数都将变为 替换值,使用标准 图书馆。MessageSourceMessageFormat - 
String getMessage(String code, Object[] args, Locale loc):基本相同 前一种方法,但有一个区别:不能指定默认消息。如果 找不到消息,将引发 A。NoSuchMessageException - 
String getMessage(MessageSourceResolvable resolvable, Locale locale):所有属性 在上述方法中也包装在名为 的类中,您可以将其与此方法一起使用。MessageSourceResolvable 
加载 an 时,它会自动搜索在上下文中定义的 bean。Bean 必须具有名称 。如果这样的 bean
,则所有对上述方法的调用都会委托给消息源。如果没有
message source 时,尝试查找包含
bean 的 bean 的 intent如果是这样,它将使用该 bean 作为 .如果找不到任何消息源,则会实例化一个空函数,以便能够接受对
方法。ApplicationContextMessageSourcemessageSourceApplicationContextMessageSourceApplicationContextDelegatingMessageSource
Spring 提供了三种实现 、 和 。他们都为了实现嵌套
消息。这很少使用,但提供了编程方式
将消息添加到源。以下示例显示:MessageSourceResourceBundleMessageSourceReloadableResourceBundleMessageSourceStaticMessageSourceHierarchicalMessageSourceStaticMessageSourceResourceBundleMessageSource
<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>
该示例假定您有三个名为 的资源包,并在 Classpath 中定义。任何解决消息的请求都是
以 JDK 标准方式通过对象解析消息进行处理。对于
本示例的目的,假设上述两个资源包文件的内容
如下:formatexceptionswindowsResourceBundle
# in format.properties
message=Alligators rock!
# in exceptions.properties
argument.required=The {0} argument is required.
下一个示例显示了一个运行该功能的程序。
请记住,所有 implementations 也是 implementations,因此可以强制转换为 interface。MessageSourceApplicationContextMessageSourceMessageSource
- 
Java
 - 
Kotlin
 
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)
}
上述程序的结果输出如下:
Alligators rock!
总而言之,它在一个名为 的文件中定义,该文件
存在于 Classpath 的根目录中。bean 定义引用
通过其属性的资源包数。这三个文件是
在列表中传递给属性的 exists 作为文件位于
Classpath 和 分别称为 、 和 。MessageSourcebeans.xmlmessageSourcebasenamesbasenamesformat.propertiesexceptions.propertieswindows.properties
下一个示例显示了传递给消息查找的参数。这些参数是
转换为 Objects 并插入到 lookup 消息的占位符中。String
<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>
- 
Java
 - 
Kotlin
 
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()
The userDao argument is required.
关于国际化(“i18n”),Spring 的各种实现遵循与标准 JDK 相同的语言环境解析和回退规则。简而言之,继续定义示例
以前,如果要针对英国 () 区域设置解析邮件,请使用
将分别创建名为 、 和 、 的文件。MessageSourceResourceBundlemessageSourceen-GBformat_en_GB.propertiesexceptions_en_GB.propertieswindows_en_GB.properties
通常,区域设置解析由 应用。在以下示例中,(英国)消息所针对的区域设置 resolved 手动指定:
# in exceptions_en_GB.properties
argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
- 
Java
 - 
Kotlin
 
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)
}
运行上述程序的结果输出如下:
Ebagum lad, the 'userDao' argument is required, I say, required.
您还可以使用该接口获取对已定义的任何内容的引用。在实现该接口的 an 中定义的任何 bean 都会注入
应用程序和配置 bean 时的应用程序上下文。MessageSourceAwareMessageSourceApplicationContextMessageSourceAwareMessageSource
因为 Spring 的基于 Java 的,所以它不会合并
具有相同基本名称的捆绑包,但将仅使用找到的第一个捆绑包。
具有相同基本名称的后续消息包将被忽略。MessageSourceResourceBundle | 
作为 的替代方法,Spring 提供了一个类。此变体支持相同的捆绑包
文件格式,但比基于 JDK 的标准实现更灵活。特别是,它允许读取
文件(不仅来自 Classpath),并支持热
重新加载 bundle 属性文件(同时在两者之间有效地缓存它们)。
有关详细信息,请参见ReloadableResourceBundleMessageSource javadoc。ResourceBundleMessageSourceReloadableResourceBundleMessageSourceResourceBundleMessageSource | 
因为 Spring 的基于 Java 的,所以它不会合并
具有相同基本名称的捆绑包,但将仅使用找到的第一个捆绑包。
具有相同基本名称的后续消息包将被忽略。MessageSourceResourceBundle | 
作为 的替代方法,Spring 提供了一个类。此变体支持相同的捆绑包
文件格式,但比基于 JDK 的标准实现更灵活。特别是,它允许读取
文件(不仅来自 Classpath),并支持热
重新加载 bundle 属性文件(同时在两者之间有效地缓存它们)。
有关详细信息,请参见ReloadableResourceBundleMessageSource javadoc。ResourceBundleMessageSourceReloadableResourceBundleMessageSourceResourceBundleMessageSource | 
标准事件和自定义事件
中的事件处理是通过类和接口提供的。如果将实现该接口的 bean 部署到上下文中,则每次将 发布到 时,都会通知该 bean。
从本质上讲,这是标准的 Observer 设计模式。ApplicationContextApplicationEventApplicationListenerApplicationListenerApplicationEventApplicationContext
从 Spring 4.2 开始,活动基础设施得到了显著改进,并提供
基于注释的模型以及
能够发布任何任意事件(即,不一定
extend from (扩展自 )。当这样的对象被发布时,我们将其包装在
活动。ApplicationEvent | 
下表描述了 Spring 提供的标准事件:
| 事件 | 解释 | 
|---|---|
  | 
在初始化或刷新时发布(例如,通过
 使用界面上的方法)。
 这里,“initialized” 表示加载所有 bean,检测到后处理器 bean
 和 activated,则单例是预先实例化的,并且对象是
 随时可用。只要上下文尚未关闭,就可以触发刷新
 多次,前提是 chosen 实际上支持这样的
 “hot” 刷新。例如,支持热刷新,但不支持。  | 
  | 
使用接口上的方法启动时发布。这里,“started” 表示所有 bean 都接收到显式的 start 信号。通常,此信号用于重新启动 bean
 ,但它也可用于启动尚未
 配置为自动启动(例如,尚未在
 初始化)。  | 
  | 
使用接口上的方法停止时发布。这里,“stopped”意味着所有 bean 都接收到显式的停止信号。可以通过调用重新启动已停止的上下文。  | 
  | 
使用方法关闭 时发布
 在接口上或通过 JVM 关闭钩子。这里
 “closed” 表示所有单例 bean 都将被销毁。关闭上下文后,
 它已达到其生命周期的终点,无法刷新或重新启动。  | 
  | 
一个特定于 Web 的事件,告诉所有 bean HTTP 请求已得到处理。这
 事件在请求完成后发布。此活动仅适用于
 使用 Spring 的 .  | 
  | 
的子类添加特定于 Servlet 的上下文信息。  | 
您还可以创建和发布自己的自定义事件。以下示例显示了
简单的类来扩展 Spring 的基类:ApplicationEvent
- 
Java
 - 
Kotlin
 
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)
要发布自定义 ,请在 .通常,这是通过创建一个实现的类并将其注册为 Spring bean 来完成的。以下内容
example 显示了这样的类:ApplicationEventpublishEvent()ApplicationEventPublisherApplicationEventPublisherAware
- 
Java
 - 
Kotlin
 
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 容器检测到 implements 并自动调用 .实际上,传入的参数是 Spring
容器本身。您正在通过其界面与应用程序上下文进行交互。EmailServiceApplicationEventPublisherAwaresetApplicationEventPublisher()ApplicationEventPublisher
要接收 custom ,您可以创建一个实现的类并将其注册为 Spring bean。以下示例
显示了这样的类:ApplicationEventApplicationListener
- 
Java
 - 
Kotlin
 
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...
	}
}
请注意,它通常使用自定义事件的类型进行参数化(在前面的示例中为 )。
这意味着该方法可以保持类型安全,无需进行向下转换。
您可以根据需要注册任意数量的事件侦听器,但请注意,默认情况下,事件侦听器同步接收事件。
这意味着该方法会阻塞,直到所有侦听器都处理完事件。
这种同步和单线程方法的一个优点是,当侦听器接收到事件时,
如果事务上下文可用,它将在 publisher 的事务上下文中运行。
如果需要其他事件发布策略,例如默认为异步事件处理,
请参阅 Spring 的 ApplicationEventMulticaster 接口的 javadoc
和 SimpleApplicationEventMulticaster 实现
对于可以应用于自定义 “applicationEventMulticaster” bean 定义的配置选项。
在这些情况下,不会传播 ThreadLocals 和日志记录上下文以进行事件处理。
有关可观察性问题的更多信息,请参阅@EventListener可观测性部分。ApplicationListenerBlockedListEventonApplicationEvent()publishEvent()
以下示例显示了用于注册和配置每个 上面的类:
<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>
把它们放在一起,当 bean 的方法是
调用,如果存在任何应阻止的电子邮件,则发布 Custom Event 类型。bean 注册为 an 并接收 ,此时它可以
通知相关方。sendEmail()emailServiceBlockedListEventblockedListNotifierApplicationListenerBlockedListEvent
| Spring 的事件机制是为 Spring bean 之间的简单通信而设计的 在同一应用程序上下文中。但是,对于更复杂的企业 集成需求,单独维护的 Spring 集成项目提供了 完全支持构建轻量级、面向模式、事件驱动的 构建在众所周知的 Spring 编程模型之上的架构。 | 
基于注释的事件侦听器
您可以使用注释在托管 Bean 的任何方法上注册事件侦听器。可以按如下方式重写:@EventListenerBlockedListNotifier
- 
Java
 - 
Kotlin
 
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...
	}
}
方法签名再次声明它监听的事件类型, 但是,这一次,使用灵活的名称,并且没有实现特定的侦听器接口。 事件类型也可以通过泛型缩小范围,只要实际的事件类型 在其 implementation hierarchy 中解析泛型参数。
如果你的方法应该监听多个事件,或者你想用 no 参数,也可以在 Annotation 本身上指定事件类型。这 以下示例显示了如何执行此操作:
- 
Java
 - 
Kotlin
 
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
	// ...
}
@EventListener(ContextStartedEvent::class, ContextRefreshedEvent::class)
fun handleContextStart() {
	// ...
}
还可以使用属性
定义 SPEL 表达式的注释中,该表达式应匹配
以实际调用特定事件的方法。condition
以下示例显示了如何重写我们的通知器,以便仅在事件的属性等于 :contentmy-event
- 
Java
 - 
Kotlin
 
@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...
}
每个表达式都根据专用上下文进行计算。下表列出了
项,以便您可以将它们用于条件事件处理:SpEL
| 名字 | 位置 | 描述 | 例 | 
|---|---|---|---|
事件  | 
root 对象  | 
实际的 .  | 
  | 
Arguments 数组  | 
root 对象  | 
用于调用方法的参数(作为对象数组)。  | 
  | 
参数名称  | 
评估上下文  | 
特定方法参数的名称。如果名称不可用
 (例如,因为代码是在没有标志的情况下编译的),单个
 参数也可以使用语法 where 表示
 argument index (从 0 开始)。  | 
  | 
请注意,这允许您访问基础事件,即使您的方法
signature 实际上是指已发布的任意对象。#root.event
如果您需要发布事件作为处理其他事件的结果,则可以更改 method signature 返回应发布的事件,如下例所示:
- 
Java
 - 
Kotlin
 
@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...
}
| 异步侦听器不支持此功能。 | 
该方法为它处理的每个 FOR EACH 发布一个 new。如果需要发布多个事件,可以返回
a 或事件数组。handleBlockedListEvent()ListUpdateEventBlockedListEventCollection
异步侦听器
如果您希望特定侦听器异步处理事件,则可以重用常规@Async支持。
以下示例显示了如何执行此操作:
- 
Java
 - 
Kotlin
 
@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
}
使用异步事件时,请注意以下限制:
- 
如果异步事件侦听器抛出 ,则不会传播到 访客。有关更多详细信息,请参阅
AsyncUncaughtExceptionHandler。Exception - 
异步事件侦听器方法无法通过返回 价值。如果需要发布另一个事件作为处理结果,请注入
ApplicationEventPublisher以手动发布事件。 - 
默认情况下,不会传播 ThreadLocals 和日志记录上下文以进行事件处理。 有关可观测性问题的更多信息
,请参阅@EventListener可观测性部分。 
对侦听器进行排序
如果需要在调用另一个侦听器之前调用另一个侦听器,则可以将 Comments 添加到方法声明中,如下例所示:@Order
- 
Java
 - 
Kotlin
 
@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...
}
泛型事件
您还可以使用泛型来进一步定义事件的结构。考虑使用 where 是创建的实际实体的类型。例如,您
可以创建以下侦听器定义以仅接收 :EntityCreatedEvent<T>TEntityCreatedEventPerson
- 
Java
 - 
Kotlin
 
@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
	// ...
}
@EventListener
fun onPersonCreated(event: EntityCreatedEvent<Person>) {
	// ...
}
由于类型擦除,仅当触发的事件解析泛型
事件侦听器过滤的参数(即类似 )。class PersonCreatedEvent extends EntityCreatedEvent<Person> { … }
在某些情况下,如果所有事件都遵循相同的
结构(如上例中的事件所示)。在这种情况下,
您可以实现以指导框架超越运行时
环境提供。以下事件演示如何执行此操作:ResolvableTypeProvider
- 
Java
 - 
Kotlin
 
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 | 
最后,与经典实现一样,实际的多播
在运行时通过上下文范围发生。默认情况下,这是调用方线程中的同步事件发布。
这可以通过 “applicationEventMulticaster” bean 定义来替换/自定义。
例如,用于异步处理所有事件和/或处理侦听器异常:ApplicationListenerApplicationEventMulticasterSimpleApplicationEventMulticaster
@Bean
ApplicationEventMulticaster applicationEventMulticaster() {
	SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
	multicaster.setTaskExecutor(...);
	multicaster.setErrorHandler(...);
	return multicaster;
}
从 Spring 4.2 开始,活动基础设施得到了显著改进,并提供
基于注释的模型以及
能够发布任何任意事件(即,不一定
extend from (扩展自 )。当这样的对象被发布时,我们将其包装在
活动。ApplicationEvent | 
| 事件 | 解释 | 
|---|---|
  | 
在初始化或刷新时发布(例如,通过
 使用界面上的方法)。
 这里,“initialized” 表示加载所有 bean,检测到后处理器 bean
 和 activated,则单例是预先实例化的,并且对象是
 随时可用。只要上下文尚未关闭,就可以触发刷新
 多次,前提是 chosen 实际上支持这样的
 “hot” 刷新。例如,支持热刷新,但不支持。  | 
  | 
使用接口上的方法启动时发布。这里,“started” 表示所有 bean 都接收到显式的 start 信号。通常,此信号用于重新启动 bean
 ,但它也可用于启动尚未
 配置为自动启动(例如,尚未在
 初始化)。  | 
  | 
使用接口上的方法停止时发布。这里,“stopped”意味着所有 bean 都接收到显式的停止信号。可以通过调用重新启动已停止的上下文。  | 
  | 
使用方法关闭 时发布
 在接口上或通过 JVM 关闭钩子。这里
 “closed” 表示所有单例 bean 都将被销毁。关闭上下文后,
 它已达到其生命周期的终点,无法刷新或重新启动。  | 
  | 
一个特定于 Web 的事件,告诉所有 bean HTTP 请求已得到处理。这
 事件在请求完成后发布。此活动仅适用于
 使用 Spring 的 .  | 
  | 
的子类添加特定于 Servlet 的上下文信息。  | 
| Spring 的事件机制是为 Spring bean 之间的简单通信而设计的 在同一应用程序上下文中。但是,对于更复杂的企业 集成需求,单独维护的 Spring 集成项目提供了 完全支持构建轻量级、面向模式、事件驱动的 构建在众所周知的 Spring 编程模型之上的架构。 | 
| 名字 | 位置 | 描述 | 例 | 
|---|---|---|---|
事件  | 
root 对象  | 
实际的 .  | 
  | 
Arguments 数组  | 
root 对象  | 
用于调用方法的参数(作为对象数组)。  | 
  | 
参数名称  | 
评估上下文  | 
特定方法参数的名称。如果名称不可用
 (例如,因为代码是在没有标志的情况下编译的),单个
 参数也可以使用语法 where 表示
 argument index (从 0 开始)。  | 
  | 
| 异步侦听器不支持此功能。 | 
这不仅适用于您作为
一个事件。ApplicationEvent | 
方便访问底层资源
为了最佳地使用和理解应用程序上下文,您应该熟悉
自己使用 Spring 的抽象,如 参考资料.Resource
应用程序上下文是 ,可用于加载对象。
A 实质上是 JDK 类的功能更丰富的版本。
实际上,包装的实现是 , 其中
适当。A 可以从
透明方式,包括从 Classpath、文件系统位置、任何位置
decpreable 替换为标准 URL 和其他一些变体。如果资源位置
string 是一个没有任何特殊前缀的简单路径,这些资源的来源是
特定于实际的应用程序上下文类型。ResourceLoaderResourceResourcejava.net.URLResourcejava.net.URLResource
您可以配置部署到应用程序上下文中的 Bean 来实现特殊的
回调接口 ,在
初始化时间,应用程序上下文本身作为 .
您还可以公开 type 的属性 ,以用于访问静态资源。
它们像任何其他属性一样被注入其中。您可以将这些属性指定为简单路径,并依赖于这些文本的自动转换
strings 添加到实际对象中。ResourceLoaderAwareResourceLoaderResourceResourceStringResource
提供给构造函数的一个或多个位置路径实际上是
资源字符串,并且以简单形式,根据特定的
context 实现。例如,将简单的
location path 作为 Classpath 位置。您还可以使用位置路径(资源字符串)
替换为特殊前缀来强制从 Classpath 或 URL 加载定义,
无论实际的上下文类型如何。ApplicationContextClassPathXmlApplicationContext
应用程序启动跟踪
它管理 Spring 应用程序的生命周期,并提供丰富的
围绕组件的编程模型。因此,复杂的应用程序可以具有同等的
复杂组件图和启动阶段。ApplicationContext
使用特定指标跟踪应用程序启动步骤有助于了解位置 时间花在启动阶段,但它也可以用作一种更好的方式 了解整个上下文生命周期。
(及其子类)使用 ,它收集有关各个启动阶段的数据:AbstractApplicationContextApplicationStartupStartupStep
- 
应用程序上下文生命周期(基础包扫描、配置类管理)
 - 
Bean 生命周期(实例化、智能初始化、后处理)
 - 
应用程序事件处理
 
以下是 中的插桩示例 :AnnotationConfigApplicationContext
- 
Java
 - 
Kotlin
 
// 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()
应用程序上下文已经通过多个步骤进行了检测。 记录后,可以使用特定工具收集、显示和分析这些启动步骤。 有关现有启动步骤的完整列表,您可以查看专门的附录部分。
默认实现是 no-op 变体,以实现最小的开销。
这意味着默认情况下,在应用程序启动期间不会收集任何指标。
Spring Framework 附带了一个使用 Java Flight Recorder 跟踪启动步骤的实现:。要使用此变体,您必须配置它的实例
设置为 。ApplicationStartupFlightRecorderApplicationStartupApplicationContext
如果开发人员提供自己的 subclass,或者希望收集更精确的数据,他们也可以使用 infrastructure。ApplicationStartupAbstractApplicationContext
ApplicationStartup仅用于应用程序启动期间,并且
核心容器;这绝不是 Java 分析器或
度量库,如 Micrometer。 | 
要开始收集自定义 ,组件可以直接从应用程序上下文中获取实例,使其组件实现
或在任何注射点上询问类型。StartupStepApplicationStartupApplicationStartupAwareApplicationStartup
开发人员在创建自定义启动步骤时不应使用命名空间。
此命名空间保留供 Spring 内部使用,并且可能会发生更改。"spring.*" | 
ApplicationStartup仅用于应用程序启动期间,并且
核心容器;这绝不是 Java 分析器或
度量库,如 Micrometer。 | 
开发人员在创建自定义启动步骤时不应使用命名空间。
此命名空间保留供 Spring 内部使用,并且可能会发生更改。"spring.*" | 
用于 Web 应用程序的便捷 ApplicationContext 实例化
例如,您可以使用 .当然,您也可以创建实例
使用其中一个实现以编程方式。ApplicationContextContextLoaderApplicationContextApplicationContext
您可以使用 注册 ,因为
以下示例显示:ApplicationContextContextLoaderListener
<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>
侦听器检查参数。如果参数不
存在,则侦听器将其用作默认值。当
参数确实存在,则侦听器会使用 predefined
分隔符(逗号、分号和空格),并将值用作其中
搜索应用程序上下文。还支持 Ant 样式的路径模式。
示例包括 (对于名称以 结尾且位于目录中的所有文件) 和 (对于任何子目录中的所有此类文件)。contextConfigLocation/WEB-INF/applicationContext.xmlString/WEB-INF/*Context.xmlContext.xmlWEB-INF/WEB-INF/**/*Context.xmlWEB-INF
将 Spring 部署为 Jakarta EE RAR 文件ApplicationContext
可以将 Spring 部署为 RAR 文件,将
Context 及其所有必需的 bean 类和库 JAR 在 Jakarta EE RAR 部署中
单位。这相当于引导一个独立的(仅托管的
在 Jakarta EE 环境中)能够访问 Jakarta EE 服务器设施。RAR 部署
是部署无头 WAR 文件方案的更自然的替代方案 — 实际上,
一个没有任何 HTTP 入口点的 WAR 文件,仅用于在 Jakarta EE 环境中引导 Spring。ApplicationContextApplicationContextApplicationContext
RAR 部署非常适合不需要 HTTP 入口点但
而是由消息终端节点和计划作业组成。在这种情况下,bean 可以
使用应用程序服务器资源,例如 JTA 事务管理器和 JNDI 绑定的 JDBC 实例和 JMS 实例,并且还可以注册
平台的 JMX 服务器 — 全部通过 Spring 的标准事务管理和 JNDI
和 JMX 支持工具。应用程序组件还可以与应用程序交互
server 的 JCA 通过 Spring 的抽象。DataSourceConnectionFactoryWorkManagerTaskExecutor
有关 RAR 部署中涉及的配置详细信息,请参见SpringContextResourceAdapter类的 javadoc。
要将 Spring ApplicationContext 简单部署为 Jakarta EE RAR 文件:
- 
包 所有应用程序类都合并到一个 RAR 文件(这是一个标准、JAR 文件,具有不同的 文件扩展名)。
 - 
将所有必需的库 JAR 添加到 RAR 存档的根目录中。
 - 
添加部署描述符(如
SpringContextResourceAdapter的 javadoc 中所示) 和相应的 Spring XML bean 定义文件(通常)。META-INF/ra.xmlMETA-INF/applicationContext.xml - 
将生成的 RAR 文件拖放到 Application Server 的部署目录。
 
此类 RAR 部署单元通常是独立的。它们不暴露组件
对外界,甚至对同一应用程序的其他模块也不例外。与
基于 RAR 的 RAR 通常通过与之共享的 JMS 目标进行
其他模块。例如,基于 RAR 的 RAR 还可以安排一些作业
或对文件系统中的新文件(或类似文件)做出反应。如果需要允许同步
从外部访问,它可以(例如)导出 RMI 端点,这些端点可以使用
通过同一台计算机上的其他应用程序模块。ApplicationContextApplicationContext | 
此类 RAR 部署单元通常是独立的。它们不暴露组件
对外界,甚至对同一应用程序的其他模块也不例外。与
基于 RAR 的 RAR 通常通过与之共享的 JMS 目标进行
其他模块。例如,基于 RAR 的 RAR 还可以安排一些作业
或对文件系统中的新文件(或类似文件)做出反应。如果需要允许同步
从外部访问,它可以(例如)导出 RMI 端点,这些端点可以使用
通过同一台计算机上的其他应用程序模块。ApplicationContextApplicationContext |