Spring启动过程中Application事件的监听与处理.md

这篇博客是解决一个实际问题,在解决过程中梳理SpringApplicationEvent的运行机制和使用方法。这个问题是,微服务架构下,需要依次启动多个服务,服务之间存在运行时的依赖关系,必须保证多个服务的启动顺序。所以决定从Spring的Application事件入手。

1.Application Events and Listeners

我查了一些资料,通用的解决方案是:创建一个监听类,实现org.springframework.context.ApplicationListener,并实现它的onApplicationEvent方法。
SpringApplicationEvent 有6种事件:

  • ApplicationStartingEvent:除了基础的注册监听和初始化之外,在开始运行时做任何处理动作之前发送
  • ApplicationEnvironmentPreparedEvent 在上下文中使用的环境已知,但是Context尚未创建之前发送
  • ApplicationPreparedEvent 在Spring刷新Context开始之前,而仅当加载bean定义之后发送
  • ApplicationStartedEvent 在刷新上下文之后,但在调用任何应用程序(ApplicationRunner)和命令行运行程序(CommandLineRunner)之前发送
  • ApplicationReadyEvent 在调用应用程序和命令行运行程序后发送。 它表示应用程序已准备好为请求提供服务。
  • ApplicationFailedEvent 在启动过程中出现异常

前5种事件,是Spring按照启动前后顺序,依次生成的。我们想要监听启动之前的事件和启动完成的事件,只需关注ApplicationStartingEvent和ApplicationReadyEvent
这是我的代码实现:

@Component
public class ApplicationEventListener implements ApplicationListener<SpringApplicationEvent >{
    
    @Value("${spring.application.name}")
    private String appName;
    private Logger log = Logger.getLogger(this.getClass());
    @Override
    public void onApplicationEvent(SpringApplicationEvent event) {
     
        if(event instanceof ApplicationStartingEvent) {//启动之前
   
            
        }else if(event instanceof ApplicationReadyEvent ){//启动成功之后
       
        }
    }

然而调试之后,发现监听时间并没有生效,于是去看了一下官方文档Application Events and Listeners

Some events are actually triggered before the ApplicationContext is created, so you cannot register a listener on those as a @Bean. You can register them with the SpringApplication.addListeners(…) method or the SpringApplicationBuilder.listeners(…) method.
If you want those listeners to be registered automatically, regardless of the way the application is created, you can add a META-INF/spring.factories file to your project and reference your listener(s) by using the org.springframework.context.ApplicationListener key, as shown in the following example:
org.springframework.context.ApplicationListener=com.example.project.MyListener

官方提供了2种方案:

1.1.在启动器中添加监听器,然后启动。SpringApplication.addListeners(…)或者SpringApplicationBuilder.listeners(…)。

public static void main(String[] args) {
        new SpringApplicationBuilder(DiscoveryServiceApplication.class)
            .listeners(new ApplicationEventListener())
            .run(args);
}
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(DiscoveryServiceApplication.class);
        app.addListeners(new ApplicationEventListener());
        app.run(args);
    }

1.2.从配置文件配置监听类

在META-INF/spring.factories中添加下面配置
org.springframework.context.ApplicationListener=com.xxx.listener.ApplicationEventListener

测试两种方式均有效,可以执行到监听方法。如此,我们的探索工作已经基本完成了。但是,作为研发人员不是应该有庖丁解牛的精神吗?
下面我们进行下知识的延伸。

2.实现CommandLineRunner和ApplicationRunner在Spring启动后执行

实现这两个接口同样能完成,在Spring容器启动后做一些操作的需求。他们的执行顺序是在
ApplicationStartedEvent 之后, ApplicationReadyEvent 之前执行。

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
    }

@Component
public class MyCommandLineRunner implements CommandLineRunner {
 
    @Override
    public void run(String... args) throws Exception {
    }

这两个接口传递的参数不同,可有不同的用法。
如果有多个实现类,而你需要他们按一定顺序执行的话,可以在实现类上加上@Order注解。@Order(value=整数值)。SpringBoot会按照@Order中的value值从小到大依次执行。

3.SpringApplicationEvent与ApplicationRunner的使用区别

你可能要问了,既然标题1提供了6中SpringApplicationEvent的统一处理方式,那么为什么还需要ApplicationRunner 和CommandLineRunner 这两个接口呢?

我总结了两个原因:

1.生命周期不同&#x

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值