zoukankan      html  css  js  c++  java
  • SpringBoot高级监听原理

    Java监听机制中定义了以下几个角色:

    1. 事件:Event,继承java.util.EventObject类的对象
    2. 事件源:Source,任意对象Object;
    3. 监听器:Listener,实现java.util.EventListener接口的对象

    SpringBoot的监听机制就是对Java的监听机制的封装。

    SpringBoot监听机制

    SpringBoot在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作。

    SpringBoot中可以实现的监听器接口有四个:

    1. ApplicationContextInitializer
    2. SpringApplicationRunListener
    3. CommandLineRunner
    4. ApplicationRunner
      其中第三个和第四个功能类似,只是方法的参数类型不同。

    示例

    1、新建一个工程,分别实现上述四个监听器接口(ApplicationContextInitializer:虽然名字上没有监听器字眼,但是实现机制也是监听器的原理)
    代码如下:

    ①实现 ApplicationContextInitializer 接口

    @Component
    public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {
            System.out.println("ApplicationContextInitializer...");
        }
    
    }
    

    ②实现 SpringApplicationRunListener 接口

    @Component
    public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    
        @Override
        public void starting(ConfigurableBootstrapContext bootstrapContext) {
            System.out.println("starting...项目启动中");
        }
    
        @Override
        public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
            System.out.println("environmentPrepared...环境对象开始准备");
        }
    
        @Override
        public void contextPrepared(ConfigurableApplicationContext context) {
            System.out.println("contextPrepared...上下文对象开始准备");
        }
    
        @Override
        public void contextLoaded(ConfigurableApplicationContext context) {
            System.out.println("contextLoaded...上下文对象开始加载");
        }
    
        @Override
        public void started(ConfigurableApplicationContext context) {
            System.out.println("started...上下文对象加载完成");
        }
    
        @Override
        public void running(ConfigurableApplicationContext context) {
            System.out.println("running...项目启动完成,开始运行");
        }
    
        @Override
        public void failed(ConfigurableApplicationContext context, Throwable exception) {
            System.out.println("failed...项目启动失败");
        }
    }
    

    ③实现 CommandLineRunner 接口

    @Component
    public class MyCommandLineRunner implements CommandLineRunner {
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("CommandLineRunner#run");
        }
    }
    

    ④实现 ApplicationRunner 接口

    @Component
    public class MyApplicationRunner implements ApplicationRunner {
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            System.out.println("ApplicationRunner#run");
        }
    }
    

    2、启动项目,控制台输出日志

    可以看到只有MyCommandLineRunner 和 MyApplicationRunner 监听器启动并生效了,这两种监听器功能类似,实际使用时用其中一种即可

    3、使MySpringApplicationRunListener 监听器生效

    在resources目录下新建一个META-INF目录并新建一个spring.factories文件

    文件内容为注册 MySpringApplicationRunListener 监听器

    org.springframework.context.ApplicationContextInitializer=\
      com.winson.springbootlistener.listener.MyApplicationContextInitializer
    

    再次启动项目,控制台日志如下,MySpringApplicationRunListener 生效,在banner打印之后,在spring的IOC容器启动前作用,实际应用时可以用作资源检测。

    4、使 MySpringApplicationRunListener 监听器生效

    我们在spring.factories文件将 MySpringApplicationRunListener 监听器也注册

    org.springframework.context.ApplicationContextInitializer=\
      com.winson.springbootlistener.listener.MyApplicationContextInitializer
    org.springframework.boot.SpringApplicationRunListener=\
      com.winson.springbootlistener.listener.MySpringApplicationRunListener
    

    启动程序,报异常:java.lang.NoSuchMethodException: com.winson.springbootlistener.listener.MySpringApplicationRunListener.(org.springframework.boot.SpringApplication, [Ljava.lang.String;),说明我们自定义的监听器类需要有初始化方法,而且需要两个参数(org.springframework.boot.SpringApplication, [Ljava.lang.String;),一个是SpringApplication类型的参数,一个是String数组

    我们找到 SpringApplicationRunListener 接口 的另一个实现类 EventPublishingRunListener 就有init方法,仿照该init方法,在我们自定义的实现类中也写一个init方法(参数也一致)

    添加初始化方法(带参构造方法)后如下(类上的@Component注解删除,否则报错,无法注入SpringApplication)

    public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    
        public MySpringApplicationRunListener(SpringApplication application, String[] args) {
        }
    
        @Override
        public void starting(ConfigurableBootstrapContext bootstrapContext) {
            System.out.println("starting...项目启动中");
        }
    
        @Override
        public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
            System.out.println("environmentPrepared...环境对象开始准备");
        }
    
        @Override
        public void contextPrepared(ConfigurableApplicationContext context) {
            System.out.println("contextPrepared...上下文对象开始准备");
        }
    
        @Override
        public void contextLoaded(ConfigurableApplicationContext context) {
            System.out.println("contextLoaded...上下文对象开始加载");
        }
    
        @Override
        public void started(ConfigurableApplicationContext context) {
            System.out.println("started...上下文对象加载完成");
        }
    
        @Override
        public void running(ConfigurableApplicationContext context) {
            System.out.println("running...项目启动完成,开始运行");
        }
    
        @Override
        public void failed(ConfigurableApplicationContext context, Throwable exception) {
            System.out.println("failed...项目启动失败");
        }
    }
    

    再次启动程序,控制台日志,发现 MySpringApplicationRunListener 监听器生效了,该监听器几乎作用在整个程序启动的生命周期里:

    小结:实际工作中,我们就可以利用监听器,在程序启动的不同阶段设置具体的业务功能

    下面简介SpringBoot中默认的监听器


    在依赖中,我们发现SpringBoot已经定义了各个阶段的监听器,打开具体一个查看,其它的大家可以再逐一查看。

  • 相关阅读:
    Android TextView内容过长加省略号
    PowerDesigner物理模型用法总结
    [K/3Cloud] 在设计时复制已有表单菜单或菜单项快速建立菜单
    cocos2d-x 多分辨率适配详解(转载),以前北京团队设计的游戏,也是用这套方案
    xcode 开发ios兼容性问题的上下黑边 和 coco2d-x 游戏分辨率适配 ResolutionPolicy::FIXED_WIDTH 都会引起上下黑边问题!!!
    孟岩的c++ 的学习方法,这何尝有不是做人做事的方法呢?
    Mac OS X 启用 Web 服务器
    android 64位的so文件 报错
    mac 用 brew
    C/C++语言参数传递----函数/方法 参数的指针引用传递
  • 原文地址:https://www.cnblogs.com/elnimo/p/15641367.html
Copyright © 2011-2022 走看看