SpringBoot
官方文档
1. SpringApplication
1.7.Application Events and Listeners
除了通常的Spring框架事件,比如ContextRefreshedEvent, SpringApplication还会发送一些其他的应用事件。
有些事件实际上是在ApplicationContext创建之前触发的,所以您不能在这些事件上注册一个@Bean侦听器。你可以用SpringApplication.addListeners(…)方法或SpringApplicationBuilder.listeners(…)方法注册它们。
如果您希望自动注册这些侦听器,而不管应用程序是如何创建的,那么您可以添加一个META-INF/spring。使用org.springframework.context.ApplicationListener键来引用监听器,如下例所示:
org.springframework.context.ApplicationListener=com.example.project.MyListener
当你的应用程序运行时,应用程序事件会按照以下顺序发送:
- ApplicationStartingEvent在运行开始时发送,但在任何处理之前发送,监听器(listeners )和初始化器(initializers)的注册除外。
- An
ApplicationEnvironmentPreparedEvent
is sent when theEnvironment
to be used in the context is known but before the context is created.(当已知上下文中使用的环境但在上下文创建之前,就会发送ApplicationEnvironmentPreparedEvent。) - 当ApplicationContext准备好并且ApplicationContextInitializedEvent被调用时,但是在任何bean定义被加载之前,会发送一个applicationcontextinitializalizer。
- ApplicationPreparedEvent在启动刷新之前发送,但在装入bean定义之后。
- ApplicationStartedEvent是在上下文刷新之后,但在调用任何应用程序和命令行运行程序之前发送的。
- 当
LivenessState.CORRECT
指示应用程序被认为是活动的,在这之后AvailabilityChangeEvent
将发送right - 在调用任何应用程序和命令行运行器后发送ApplicationReadyEvent。
AvailabilityChangeEvent
发送right,后与ReadinessState.ACCEPTING_TRAFFIC
去指示应用程序已准备好为请求提供服务。- 如果在启动时出现异常,将发送ApplicationFailedEvent。
上面的列表只包括绑定到一个SpringApplication的SpringApplicationEvents。除此之外,以下事件也会在ApplicationPreparedEvent之后和applicationstartdevent之前发布:
- webserverinitializeevent会在WebServer准备好后发送。ServletWebServerInitializedEvent和ReactiveWebServerInitializedEvent分别是servlet和响应式变量。
- 当ApplicationContext被刷新时,ContextRefreshedEvent被发送。
您通常不需要使用应用程序事件,但是知道它们的存在是很方便的。在内部,Spring Boot使用事件来处理各种任务。
事件监听器不应该运行可能很长时间的任务,因为它们在默认情况下在同一个线程中执行。考虑使用应用程序和命令行运行器。
应用程序事件通过使用Spring框架的事件发布机制发送。该机制的一部分确保了在子上下文中发布到监听器的事件也被发布到任何祖先上下文中的监听器。因此,如果您的应用程序使用了SpringApplication实例的层次结构,则侦听器可能会接收到相同类型的应用程序事件的多个实例。
为了允许监听器区分其上下文的事件和后代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。上下文可以通过实现ApplicationContextAware注入,如果侦听器是一个bean,则可以使用@Autowired。
常用的监听器接口:
1.ServletContextListener – 监听servletContext对象的创建以及销毁
1.1 contextInitialized(ServletContextEvent arg0) -- 创建时执行
1.2 contextDestroyed(ServletContextEvent arg0) -- 销毁时执行
2.HttpSessionListener – 监听session对象的创建以及销毁
2.2 sessionCreated(HttpSessionEvent se) -- 创建时执行
2.2 sessionDestroyed(HttpSessionEvent se) -- 销毁时执行
3.ServletRequestListener – 监听request对象的创建以及销毁
3.1 requestInitialized(ServletRequestEvent sre) -- 创建时执行
3.2 requestDestroyed(ServletRequestEvent sre) -- 销毁时执行
4.ServletContextAttributeListener – 监听servletContext对象中属性的改变
4.1 attributeAdded(ServletContextAttributeEvent event) -- 添加属性时执行
4.2 attributeReplaced(ServletContextAttributeEvent event) -- 修改属性时执行
4.3 attributeRemoved(ServletContextAttributeEvent event) -- 删除属性时执行
5.HttpSessionAttributeListener –监听session对象中属性的改变
5.1 attributeAdded(HttpSessionBindingEvent event) -- 添加属性时执行
5.2 attributeReplaced(HttpSessionBindingEvent event) -- 修改属性时执行
5.3 attributeRemoved(HttpSessionBindingEvent event) -- 删除属性时执行
6.ServletRequestAttributeListener –监听request对象中属性的改变
6.1 attributeAdded(ServletRequestAttributeEvent srae) -- 添加属性时执行
6.2 attributeReplaced(ServletRequestAttributeEvent srae) -- 修改属性时执行
6.3 attributeRemoved(ServletRequestAttributeEvent srae) -- 删除属性时执行
14. Messaging
14.2. AMQP
14.2.1. RabbiMQ support
RabbitMQ是一个基于AMQP协议的轻量级、可靠、可扩展、可移植的消息代理。Spring使用RabbitMQ通过AMQP协议进行通信。
在spring.rabbitmq.*
中,RabbitMQ配置由外部配置属性控制。例如,可以在application.yml
中声明以下部分:
spring:
rabbitmq:
host: "localhost"
port: 5672
username: "admin"
password: "secret"
或者,你也可以使用addresses属性配置相同的连接:
spring:
rabbitmq:
addresses: "amqp://admin:secret@localhost"
当以addresses属性方式指定地址时,主机和端口属性将被忽略。如果该地址使用amqps协议,则自动开启SSL支持。
更多支持的基于属性的配置选项,请参见RabbitProperties。要配置Spring AMQP使用的RabbitMQ ConnectionFactory的底层细节,定义一个ConnectionFactoryCustomizer bean。
如果上下文中存在 ConnectionNameStrategy bean
,它将自动用于命名由自动配置的 CachingConnectionFactory
创建的连接。
See Understanding AMQP, the protocol used by RabbitMQ for more details.
14.2.2. Sending a Message
Spring的AmqpTemplate和AmqpAdmin是自动配置的,你可以直接将它们自动连接到你自己的bean中,如下面的例子所示:
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final AmqpAdmin amqpAdmin;
private final AmqpTemplate amqpTemplate;
public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
this.amqpAdmin = amqpAdmin;
this.amqpTemplate = amqpTemplate;
}
public void someMethod() {
this.amqpAdmin.getQueueInfo("someQueue");
}
public void someOtherMethod() {
this.amqpTemplate.convertAndSend("hello");
}
}
RabbitMessagingTemplate可以用类似的方式注入。如果定义了MessageConverter bean,它将自动关联到自动配置的AmqpTemplate。
如果有必要,任何被定义为bean的org.springframework.amqp.core.Queue都会被自动用于在RabbitMQ实例上声明一个相应的队列。
要重试操作,可以在AmqpTemplate上启用重试(例如,在代理连接丢失的情况下):
spring:
rabbitmq:
template:
retry:
enabled: true
initial-interval: "2s"
缺省情况下禁用重试。你也可以通过声明一个RabbitRetryTemplateCustomizer bean来编程地定制RetryTemplate。
如果你需要创建更多的RabbitTemplate实例,或者你想覆盖默认设置,Spring Boot提供了一个RabbitTemplateConfigurer bean,你可以使用它来初始化一个RabbitTemplate,使用的设置和工厂使用的自动配置相同。
14.2.3. Receiving a Message
当Rabbit基础架构存在时,任何bean都可以用@RabbitListener注释来创建侦听器端点。如果没有定义RabbitListenerContainerFactory,默认的SimpleRabbitListenerContainerFactory会自动配置,你可以使用spring.rabbitmq.listener.type属性切换到直接容器。如果定义了MessageConverter或messagerrecoverer bean,它将自动与默认工厂关联。
下面的示例组件在someQueue队列上创建了一个侦听器端点:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue")
public void processMessage(String content) {
// ...
}
}
See the Javadoc of @EnableRabbit
for more details.
如果你需要创建更多的RabbitListenerContainerFactory实例,或者你想重写默认值,Spring Boot引导提供 SimpleRabbitListenerContainerFactoryConfigurer
和 DirectRabbitListenerContainerFactoryConfigurer
,您可以用它来初始化一个 SimpleRabbitListenerContainerFactory
和 DirectRabbitListenerContainerFactory
相同的设置工厂使用的自动配置。
选择哪种容器类型并不重要。这两个bean是由自动配置公开的。
例如,下面的配置类公开了另一个使用特定MessageConverter的工厂:
@Configuration(proxyBeanMethods = false)
public class MyRabbitConfiguration {
@Bean
public SimpleRabbitListenerContainerFactory myFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
ConnectionFactory connectionFactory = getCustomConnectionFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(new MyMessageConverter());
return factory;
}
private ConnectionFactory getCustomConnectionFactory() {
return ...
}
}
然后你可以在任何 @RabbitListener
注解的方法中使用factory,如下所示:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue", containerFactory = "myFactory")
public void processMessage(String content) {
// ...
}
}
您可以启用重试来处理侦听器抛出异常的情况。默认情况下,使用RejectAndDontRequeueRecoverer,但您可以定义自己的MessageRecoverer。当重试次数耗尽时,消息将被拒绝,并被丢弃或路由到一个死信交换(如果代理配置了这样做的话)。缺省情况下,禁用重试功能。你也可以通过声明一个RabbitRetryTemplateCustomizer bean来编程地定制RetryTemplate。
重要事项:
默认情况下,如果禁用重试并且侦听器抛出异常,传递将无限期重试。您可以通过两种方式修改此行为:将defaultrequeuereject属性设置为false,以便尝试重新提交,或抛出一个AmqpRejectAndDontRequeueException来表示应该拒绝消息。后者是在启用重试并且达到传递尝试的最大次数时使用的机制。