Spring 学习之扩展点总结之内置事件(四)

Spring 源码系列

1、Spring 学习之扩展点总结之后置处理器(一)
2、Spring 学习之扩展点总结之后置处理器(二)
3、Spring 学习之扩展点总结之自定义事件(三)
4、Spring 学习之扩展点总结之内置事件(四)
5、Spring 学习之扩展点总结之@Import(五)
6、Spring 学习之AOP总结之基础介绍(六)
7、Spring 学习之AOP总结之实现代理(七)
8、SpringBoot 学习之自动配置基本原理(八)
9、SpringBoot 学习之启动原理(九)
10、ElasticSearch学习随笔之SpringBoot Starter 操作
11、图数据库 Neo4j 学习之SpringBoot整合
12、SpringBoot 学习之常用 Filter / Advice 总结
13、SpringBoot+FastJson 优雅的过滤 Response Body
14、Spring Security + Oauth2 认证授权

前言

在 Spring学习之扩展点总结之自定义事件中介绍了什么是 Event事件以及自定义事件的用法,但是还没有完,Spring还提供了四种内置事件供我们使用,本文就主要讲解Spring 内置事件。

一、什么是内置事件?

什么是 Spring 内置事件,在 自定义事件 篇中介绍了 Spring 事件以及自定义事件的用法,在 Spring 内部也整合了不同的事件供我们使用,就是内置事件。

内置事件总共有 四种,如下:

事件名称事件说明
ContextStartedEvent此 Start 事件是当Spring容器启动时发布,即调用 start() 方法是执行,意味着所有Lifecyc Bean 都监听到了 start 事件。
ContextRefreshedEvent此 Refreshed 事件是当容器实例化时发布,即执行 refresh() 方法,此时所有的 Bean 都已加载,后置处理器被激活,容器中所有的对象就可以使用,如果容器支持热重载,则 refresh 可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持)
ContextStoppedEvent此 stoped 事件是当容器停止是发布,即调用 stop() 方法,所有的 Lifecyc Bean 都监听到了 stop 事件,关闭的容器可以通过 start() 重启。
ContextClosedEvent此 closed 事件和 stop 事件类似,当容器关闭是发布,即调用 close() 方法,意味着容器所有的 Bean 都已被销毁,和 stoped 事件不同点就是,容器在 stop() 之后可以通过 start() 重启,但是 close() 之后则不能重启或 refresh() 。
RequestHandledEvent此 Request handled 事件只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布

Spring 内置事件已经提供好了,我们只需要实现监听器即可,内置监听器类图如下:

内置监听器类图

二、内置事件调用

因为 Spring 提供的内置事件是在 Spring 容器启动过程中执行的,所以我们可以实现完四个事件监听器,对四个内置事件进行监听,然后统一调用。

2.1 ContextStartedEvent

@Component
public class ContextStartedEventListener {

	@EventListener(ContextStartedEvent.class)
	public void onApplicationEvent(ContextStartedEvent event){
		System.out.println("进入ContextStartedEvent事件监听");
		if(event.getApplicationContext().getParent() == null){
			System.out.println("Spring 容器初始化完成了,执行事件方法。");
			System.out.println("================================");
		}
	}
}

2.2 ContextRefreshedEvent

@Component
public class ContextRefreshEventListener {

	@EventListener(ContextRefreshedEvent.class)
	public void onApplicationEvent(ContextRefreshedEvent event){
		System.out.println("进入ContextRefreshedEvent事件监听");
		if(event.getApplicationContext().getParent() == null){
			System.out.println("容器加载完毕...头一个事件监听");
			System.out.println("================================");
		}
	}
}

2.3 ContextStoppedEvent

@Component
public class ContextStoppedEventListener {
	
	@EventListener(ContextStoppedEvent.class)
	public void onApplicationEvent(ContextStoppedEvent event){
		System.out.println("进入ContextStopEvent事件监听");
		if (event.getApplicationContext().getParent() == null) {
			System.out.println("spring容器停止发布");
			System.out.println("================================");
		}
	}
}

2.4 ContextClosedEvent

@Component
public class ContextClosedEventListener {
	@EventListener(ContextClosedEvent.class)
	public void onApplicationEvent(ContextClosedEvent event){
		System.out.println("进入ContextClosedEvent事件监听");
		System.out.println("spring 容器关闭......");
		System.out.println("================================");
	}
}

2.5 初始化容器测试

在main 方法中实例化容器(AnnotationConfigApplicationContext),这里定义的类型也是 AnnotationConfigApplicationContext 类型的,如果定义成了 ApplicationContext 上下文类型,是调用不了 start、stop、close 这几个方法的,因为 Spring 的内置事件是单独 EventListener 接口。

@ComponentScan("com.self.test.event")
@EnableAsync
public class MainStartApp {

	public static void main(String[] args) throws Exception {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainStartApp.class);
		applicationContext.start();
		applicationContext.stop();
		applicationContext.close();
	}
}

执行测试结果:
内置事件测试结果

从测试结果中可以看到,这四个内置事件都执行了。
注意:并没有在 main 方法中调用 refresh() 方法,也执行了 ContextRefreshedEvent 事件,那是因为 Spring 在启动容器是内部就调用了 refresh() 方法。

三、内置事件监听器的异步调用

其实在自定义事件篇中也讲到过异步使用,内置事件当然也可以用 @Async 注解来实现异步执行。

@Component
public class ContextStoppedEventListener {

	@Async
	@EventListener(ContextStoppedEvent.class)
	public void onApplicationEvent(ContextStoppedEvent event){
		System.out.println("进入ContextStopEvent事件监听");
		if (event.getApplicationContext().getParent() == null) {
			System.out.println("spring容器停止发布");
			System.out.println("================================");
		}
	}
}

四、内置事件监听器的具体使用

上面说到了 Spring 的四个内置使用如何调用,可以说是简单便捷,但是具体的没事内置事件中如何使用Spring 提供的功能,我们来简单研究一下,以 ContextRefreshedEvent 为例,因为这个事件的监听器在 Spring 启动的时候就会调用到,代码如下:
1、新建一个 UserService 服务类,并且提供 init() 的初始化方法。

@Component
public class UserService {

	public void init(){
		System.out.println("执行 UserService 初始化方法");
	}
}

2、在 ContextRefreshedEvent 事件中通过上下文获取到 UserService 服务实体并且调用 init() 方法。

@Component
public class ContextRefreshEventListener {

	@EventListener(ContextRefreshedEvent.class)
	public void onApplicationEvent(ContextRefreshedEvent event){
		System.out.println("进入ContextRefreshedEvent事件监听");
		if(event.getApplicationContext().getParent() == null){
			System.out.println("容器加载完毕...头一个事件监听");
			System.out.println("================================");
		}
		UserService userService = event.getApplicationContext().getBean(UserService.class);
		userService.init();
		System.out.println("UserServiceImpl:" + userService);
	}
}

3、执行测试

测试结果

从测试结果中我们可以看到,在 ContextRefreshedEvent 的监听器中,我们可以通过 event.getApplicationContext() 获取到容器上下文,然后通过 getBean() 方法获取到 UserService 的 Bean 实例,然后就可以调用 UserService.init() 方法去做一下业务逻辑了,在项目中这样的操作很多;
也可以通过上下文对获取到的 Bean 进行修改操作,类似于Spring提供的后置处理器。

四、总结

本文对 Spring 的四个内置事件实现进行了讲解,使用注解的方式使用起来可以说是简单快捷,通过内置事件提供的 ContextXxxxxEvent 参数我们可以获取到容器的上下文,就可以做很多操作了,比如在项目启动的时候进行常用缓存的加载,或者是缓存清理操作,或者是启动日志打印等等。
其实有些功能用起来很方便,也很简单,在此记录一下可以加深印象,自己亲手总结,测试写出来的东西,自己看的最明白,自己也记得最牢固,也有点成就感,万一火了呢。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值