文章目录
- 摘要
- 正文
- jdk事件
- Spring事件
- Spring事件监听
- ApplicationContext主动监听
- 注解监听
- Bean监听
- Spring事件发布
- 总结
摘要
在这篇文章我们将介绍Spring的事件机制,包括Spring内置事件、自定义事件、事件监听、事件发布、事件广播机制、事件异常处理等内容。Spring事件是对JDK提供的观察者模式,结合Spring容器进行的深度扩展,了解Spring提供了那些内置事件,以及如何自定义事件可以让我们很方便的对Spring框架进行扩展,来实现更多更丰富的功能。🦾
正文
jdk事件
说到事件监听,不得不提到观察者模式,jdk提供了简单的观察者模式工具类方便我们使用,它包括 java.util.Observable
类和java.util.Observer
接口,其中 Observer
作为观察者来监听事件, Observable
作为事件发布者。简单的样例代码如下
public class JdkObserver {
public static void main(String[] args) {
MyObservable observable = new MyObservable();
//监听事件
observable.addObserver(new MyObserver());
//发布事件
observable.notifyObservers("测试事件发布");
}
}
class MyObservable extends Observable{
@Override
public void notifyObservers(Object arg) {
super.setChanged();
super.notifyObservers(new EventObject(arg));
super.clearChanged();
}
}
class MyObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
EventObject event = (EventObject) arg;
System.out.println("收到事件:"+event);
}
}
Spring事件
通过上例可以发现,要想监听一个事件,有三个要素,①事件本身EventObject
、②发布事件的动作notifyObservers
、③监听事件addObserver
。Spring标准事件对Java标准事件EventObject
进行了扩展,添加了一个事件发生时间戳属性,同时Spring内置了一系列的应用上下文事件,方便调用
Spring内置的上下文应用事件包括:
- Spring应用上下文就绪事件:ContextRefreshedEvent
- Spring应用上下文启动事件:ContextStartedEvent
- Spring应用上下文停止事件:ContextStoppedEvent
- Spring应用上下文关闭事件:ContextClosedEvent
以上四个内置事件都继承自 ApplicationContextEvent
这个类,而 ApplicationContextEvent
继承了 ApplicationEvent
,ApplicationEvent
继承自 Java.util.EventObject
。整体的类继承关系如下图所示
在实际应用中,可以监听以上四个内置事件,也可以直接监听 ApplicationEvent
,实现对所有Spring事件的监听,如果以上几种都不能满足需求,也可以通过实现 ApplicationEvent
或 ApplicationContextEvent
来自定义事件。一个简单的自定义事件如下代码所示
public class MyCustomEvent extends ApplicationContextEvent {
public MyCustomEvent(Object source) {
super(source);
}
}
Spring事件监听
在Spring中监听事件的方法有很多种,主要包括
- 通过ApplicationContext主动监听
- 通过@EventListener注解监听
- 注册一个
ApplicationEventListener
类型的Bean
ApplicationContext主动监听
通过ApplicationContext
主动添加事件监听,需要能获取到 ApplicationContext
这个应用上下文,最简单的方式是实现 ApplicationContextAware
接口,关于 ApplicationContextAware
的具体内容可以看这篇文章
@Component
public class SpringEventComponent implements ApplicationContextAware {
private Logger logger= LoggerFactory.getLogger(SpringEventComponent.class);
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(applicationContext instanceof AbstractApplicationContext){
((AbstractApplicationContext) applicationContext).addApplicationListener(new ApplicationListener<ApplicationEvent>() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
logger.info("接收到事件:"+event);
}
});
}
this.context=applicationContext;
}
}
注解监听
通过注解注册事件监听的方式很简单,只需要在方法上使用 @EventListener
注解即可
@Component
public class SpringEventComponent implements ApplicationContextAware {
private Logger logger= LoggerFactory.getLogger(SpringEventComponent.class);
private ApplicationContext context;
@EventListener
public void annoEventListener(ApplicationEvent event){
logger.info("Annotation接收到事件:"+event);
}
}
基于注解的这种方式,还支持通过 @Async
注解实现异步事件
@EventListener
@Async
public void annoEventListener(ApplicationEvent event){
logger.info("Annotation接收到事件:"+event);
}
//需要在主类种启动异步支持
@SpringBootApplication
@EnableAsync
public class SpringNotesApplication {
public static void main(String[] args) {
SpringApplication.run(SpringNotesApplication.class, args);
}
}
同步和异步的区别在于,同步的方式事件监听在Main线程,异步的方式是在一个新的线程,可以通过日志打印查看具体的执行线程,异步的效果如下
2024-01-15 11:41:00.854 [task-3] INFO top.sunyog.spring.notes.event.SpringEventComponent - Annotation接收到事件:org.springframework.boot.context.event.ApplicationStartedEvent[source=org.springframework.boot.SpringApplication@6feb8a8c]
同步的效果如下
2024-01-15 11:43:24.469 [main] INFO top.sunyog.spring.notes.event.SpringEventComponent - Annotation接收到事件:org.springframework.boot.context.event.ApplicationStartedEvent[source=org.springframework.boot.SpringApplication@726a6b94]
Bean监听
通过注册一个 ApplicationListener
类型的Bean也可以实现事件的监听。注册Bean的方式也是多种多样的,如:①可以通过@Bean注解注册一个Bean;②通过ApplicationContext注册Bean;③通过自定义BeanDefinition注册Bean。要了解Bean的配置或注册方式,可以查看这篇文章
以下代码是通过@Bean注解注册一个ApplicationListener
@Bean
public ApplicationListener applicationListener(){
ApplicationListener<ApplicationEvent> listener = new ApplicationListener<ApplicationEvent>(){
@Override
public void onApplicationEvent(ApplicationEvent event) {
logger.info("@Bean接收到事件:"+event);
}
};
return listener;
}
Spring事件发布
Spring内置了事件发布器 ApplicationEventPublisher
,通过它可以实现自定义事件的发布,事件发布器可以通过依赖注入获取,也可以通过实现 ApplicationEventPublisherAware
来获取。发布一个简单的自定义事件的代码如下
@Component
public class SpringEventComponent implements ApplicationEventPublisherAware, ApplicationRunner {
private Logger logger= LoggerFactory.getLogger(SpringEventComponent.class);
private ApplicationEventPublisher publisher;
@Bean
public ApplicationListener applicationListener(){
ApplicationListener<ApplicationEvent> listener = new ApplicationListener<ApplicationEvent>(){
@Override
public void onApplicationEvent(ApplicationEvent event) {
logger.info("@Bean接收到事件:"+event);
}
};
return listener;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher=applicationEventPublisher;
}
@Override
public void run(ApplicationArguments args) throws Exception {
this.publisher.publishEvent(new MyCustomEvent("自定义事件发布ing"));
}
}
事件监听结果为
2024-01-15 14:14:17.201 [main] INFO top.sunyog.spring.notes.event.SpringEventComponent - @Bean接收到事件:top.sunyog.spring.notes.event.MyCustomEvent[source=自定义事件发布ing]
在 ApplicationEventPublisher
中的 publishEvent(Objecy)
方法可以发布 PayloadApplicationEvent
事件,这是Spring为简化事件发布而推出的一类事件,可以直接通过 ApplicationEventPublisher#publishEvent(Object)
方法发布该类型的事件,PayloadApplicationEvent
事件发布时除了事件本身外,还包含一个事件消息,publishEvent(Object )
方法中的Object就是这个消息。
@Component
public class SpringEventComponent implements ApplicationEventPublisherAware, ApplicationRunner {
private Logger logger= LoggerFactory.getLogger(SpringEventComponent.class);
private ApplicationEventPublisher publisher;
@EventListener
public void annoEventListener(PayloadApplicationEvent event){
Object payload = event.getPayload();
logger.info("@EventListener接收到payload事件:"+event+",msg: "+payload);
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher=applicationEventPublisher;
}
@Override
public void run(ApplicationArguments args) throws Exception {
//
this.publisher.publishEvent("payload事件发布ing,这是一个消息");
}
}
事件监听结果如下
2024-01-15 15:02:40.463 [main] INFO top.sunyog.spring.notes.event.SpringEventComponent - @EventListener接收到payload事件:org.springframework.context.PayloadApplicationEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e35bc3d, started on Mon Jan 15 15:02:39 CST 2024],msg: payload事件发布ing,这是一条消息
除了 ApplicationEventPublisher
之外,在Spring中还可以通过 ApplicationEventMulticaster
广播器来发布事件,广播器是一个内置的SpringBean,可以通过依赖查找或依赖注入的方式获得,广播器发布事件的方式如下
public class SpringEventComponent implements ApplicationRunner {
@Resource
private ApplicationEventMulticaster multicaster;
@Override
public void run(ApplicationArguments args) throws Exception {
this.multicaster.multicastEvent(new MyCustomEvent("自定义事件广播ing"));
}
}
事件监听结果
2024-01-15 14:20:38.008 [main] INFO top.sunyog.spring.notes.event.SpringEventComponent - @Bean接收到事件:top.sunyog.spring.notes.event.MyCustomEvent[source=自定义事件广播ing]
这里的时间广播器 ApplicationEventMulticaster
是一个接口,在Spring中,所有的事件都通过它来广播出来,具体的类继承关系图包括
在 AbstractApplicationEventMulticaster
类的 retrieverCache
属性中保存了所有已注册的 ApplicationListener
,在Spring的应用上下文中保存了 SimpleApplicationEventMulticaster
,当事件发布时,通过这个类向所有的事件监听器广播事件,即实现了事件的监听。
在Spring4.1版本中,引入了事件异常处理机制,在 SimpleApplicationEventMulticaster
类中增加了一个 setErrorHandler
方法,可以用来设定事件异常时进行的操作,如事件监听时发生如下异常
@Bean
public ApplicationListener applicationListener(){
ApplicationListener<MyCustomEvent> listener = new ApplicationListener<MyCustomEvent>(){
@Override
public void onApplicationEvent(MyCustomEvent event) {
throw new RuntimeException("事件异常");
}
};
return listener;
}
这时,可以通过以下方式设置事件异常处理
@Component
public class SpringEventComponent implements ApplicationEventPublisherAware, ApplicationRunner {
private Logger logger= LoggerFactory.getLogger(SpringEventComponent.class);
private ApplicationEventPublisher publisher;
@Resource
private ApplicationEventMulticaster multicaster;
@Override
public void run(ApplicationArguments args) throws Exception {
//设置事件异常处理器
if (this.multicaster instanceof SimpleApplicationEventMulticaster){
((SimpleApplicationEventMulticaster) multicaster).setErrorHandler(handler->{
String message = handler.getMessage();
logger.info("事件发生异常:"+message);
});
}
this.publisher.publishEvent(new MyCustomEvent("自定义事件发布ing"));
}
}
发生事件异常时,的打印结果
2024-01-15 15:25:34.890 [main] INFO top.sunyog.spring.notes.event.SpringEventComponent - 事件发生异常:事件异常
总结
本文主要介绍了Spring中的事件机制,包括事件监听、事件发布、自定义事件等。Spring中的事件实际上是对jdk提供的观察者模式的深入扩展,结合Spring容器实现了事件的深度扩展。在Spring框架项目的开发过程中,我们可以应用事件机制,实现一些常用的功能,如对容器的不同行为(启动、停止、刷新等)进行扩展。
📩 联系方式
邮箱: qijilaoli@foxmail.com
掘金: 我的掘金
CSDN: 我的CSDN❗版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问我的博客首页