22 ApplicationEvent
Spring允许我们在ApplicationContext中发布ApplicationEvent事件,然后对应的ApplicationListener可以用来监听对应的事件。当发布了一个ApplicationEvent后,在对应bean容器中实现了ApplicationListener接口的bean实例都会接收到对应的通知,即对应的ApplicationListener回调方法将会被调用。
22.1内置事件
Spring自身已经为我们提供了几个ApplicationEvent,它们会由Spring在相应的时间自动进行发布,用户如果有需要可以对它们进行监听。具体来说有如下几种类型。
22.1.1 ContextRefreshedEvent
ContextRefreshedEvent将在对应的ApplicationContext调用refresh()方法时进行发布,这也包括直接使用配置文件等进行对应的ApplicationContext初始化时,因为在这个时候也会调用对应的refresh()方法。而在refresh()方法中是在该方法的最后才进行ContextRefreshedEvent发布的,也就是说在发布ContextRefreshedEvent时对应ApplicationContext中的bean定义都已经加载完成,对应的BeanFactoryPostProcessor都执行过了,需要实例化的bean也都已经实例化了。
22.1.2 ContextStartedEvent
ContextStartedEvent将在对应的ApplicationContext调用start()方法时进行发布。此时已经对所有实现了LifeCycle接口的bean回调了对应的start()方法。
22.1.3ContextStoppedEvent
ContextStoppedEvent将在对应的ApplicationContext调用stop()方法时进行发布。此时已经对所有实现了LifeCycle接口的bean回调了对应的stop()方法。
22.1.4ContextClosedEvent
ContextClosedEvent将在对应的ApplicationContext调用close()方法时进行发布。此时所有的资源都已经销毁了。ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent和ContextClosedEvent都继承自ApplicationContextEvent,因为它们都是针对ApplicationContext的事件。
22.1.5 ServletRequestHandledEvent
ServletRequestHandledEvent将在Spring处理了一个HttpRequest请求后进行发布,即对应的HttpRequest已经完成了。ServletRequestHandledEvent只能在使用DispatcherServlet时使用,当DispatcherServlet处理完一个HttpRequest请求后将发布一个ServletRequestHandledEvent。ServletRequestHandledEvent继承自RequestHandledEvent,所以当我们需要监听RequestHandledEvent时也可以监听ServletRequestHandledEvent。
22.2 自定义事件
Spring能够发布的事件是ApplicationEvent,其是一个继承了EventObject的抽象类。其源码如下所示,我们可以看到其只有一个构造方法,且必须传入一个对象作为当前事件发布的发布者。
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened */
private final long timestamp;
/**
* Create a new ApplicationEvent.
* @param source the component that published the event (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
用户如果需要自定义事件则是自定义一个继承ApplicationEvent的类,除了提供构造父类必须要有的source对象以外,其它信息都可以由用户自定义。如下我们就简单的实现了一个自定义的ApplicationEvent,那么在之后进行事件发布时就可以使用自定义的MyApplicationEvent来作为ApplicationEvent进行发布了。
public class MyApplicationEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
public MyApplicationEvent(Object source) {
super(source);
}
}
22.3 事件发布
事件的发布是由ApplicationEventPublisher接口中的publishEvent()方法定义的,其定义如下。
public interface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
}
ApplicationContext接口继承了ApplicationEventPublisher接口,所以我们可以直接使用ApplicationContext来进行事件的发布。如下示例中我们就给Hello注入了一个ApplicationContext,然后在调用其doSomething()方法时通过注入的ApplicationContext发布了一个自定义的MyApplicationEvent。
@Component
public class Hello {
@Autowired
private ApplicationContext context;
public void doSomething() {
System.out.println("----do something....");
//发布一个自定义的MyApplicationEvent
context.publishEvent(new MyApplicationEvent(this));
}
}
除了直接使用ApplicationContext进行事件发布外,Spring还给我们提供了一个用于发布事件的ApplicationEventPublisher接口对应的Aware接口——ApplicationEventPublisherAware,该接口跟Spring提供的其它Aware接口一样,当一个bean实现了该接口以后,Spring在实例化对应的bean后将调用其中的回调方法以传入一个ApplicationEventPublisher,通常就是传递的当前的ApplicationContext对象。所以我们还可以让我们的bean实现ApplicationEventPublisherAware接口,然后使用Spring传入的ApplicationEventPublisher发布对应的事件。所以上述示例我们也可以把它改成实现ApplicationEventPublisherAware的方式,示例如下。
@Component
public class Hello implements ApplicationEventPublisherAware {
private ApplicationEventPublisher eventPublisher;
public void doSomething() {
System.out.println("----do something....");
//发布一个自定义的MyApplicationEvent
this.eventPublisher.publishEvent(new MyApplicationEvent(this));
}
public void setApplicationEventPublisher(
ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
}
22.4 事件监听
事件监听需要定义对应的监听器,Spring中用于监听ApplicationEvent的监听器是通过ApplicationListener来定义的。ApplicationListener是一个接口,其定义如下,我们可以看到该接口中使用了泛型,即可以指定只监听某种类型的ApplicationEvent。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
ApplicationListener每次监听到对应的ApplicationEvent后都将调用其onApplicationEvent()方法。所以如果我们想定义一个只监听之前自定义的MyApplicationEvent的监听器,则可以如下定义,如果想监听所有的ApplicationEvent,则可以将泛型指定为ApplicationEvent,即将如下的MyApplicationEvent改成ApplicationEvent。
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println(event.getSource() + "****************" + event.getTimestamp());;
}
}
光实现了ApplicationListener接口,对应的监听器还监听不到对应的事件。我们需要把它们定义bean容器中的一个bean,这样当Spring发布了一个事件后就会将其传递给相匹配的监听器。所以针对于上述监听器,我们可以在基于XML进行配置时在对应的XML配置文件中进行如下配置。
<bean class="com.app.MyApplicationListener"/>
如果是基于注解的扫描则可以在MyApplicationListener上使用@Component等注解进行标注。
(注:本文是基于Spring4.1.0所写)
相关推荐
SpringCloud——分布式配置中心(Spring Cloud Config)之高可用的分布式配置中心
SpringCloud——消息总线(Bus)之Spring Cloud Bus将分布式系统的节点与轻量级消息代理链接。
SpringCloud——断路器(Hystrix)之Ribbon使用断路器和Feign使用断路器
SpringCloud——分布式跟踪(Sleuth)之Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案。
Spring boot——@DeclareParents例子...
SpringCloud——服务注册(consul)之Consul通过HTTP API和DNS提供服务发现服务。
Spring系列——MVC框架整合.md
SpringCloud——路由器和过滤器(Zuul)之微服务网关的实现
关于Spring方面的常见面试题
MyBatis与Spring整合——通过官方文档进行最简单的整合
Spring总结——田超凡【原创田超凡,已申请版权,禁止随意转发,侵权仿冒必究】
所有Spring——jar详细介绍 所有Spring——jar详细介绍 所有Spring——jar详细介绍
Zookeeper作为注册中心搭建SpringCloud实现服务注册及发现
NULL 博文链接:https://ylxy3058.iteye.com/blog/2225314
我们从一个简单的容器开始,一步步的重构,最后实现一个基本的Spring框架的雏形,为了帮助我们更加深入的理解Spring的IoC...【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)
Spring.NET学习笔记22——整合WCF(应用篇) http://www.cnblogs.com/GoodHelper/archive/2010/05/15/SpringNet_Wcf.html
SpringCloud-Eureka实现服务的注册与发现,创建服务注册中心(eureka-server)和服务提供者 (eureka-client)
SpringCloud —— Eureka 集群 SpringCloud —— 服务注册进 Eureka 集群 SpringCloud —— Eureka 自我保护 SpringCloud —— SpringCloud Consul 实现服务注册中心 SpringCloud —— 三个注册中心的异同点 ...
NULL 博文链接:https://snowolf.iteye.com/blog/236264