不知鱼

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1 、使用接口ApplicationRunner和CommandLineRunner

这两个接口都是在容器运行后执行的,如下图示

 如果项目需要在系统启动时,初始化资源,可以继承这两个接口,实现诸如缓存预热、DB连接等。

实现ApplicationRunner接口

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("缓存预热~");
        System.out.println("DB连接~");
        System.out.println("日志系统初始化~");
        System.out.println("资源文件初始化~");
        System.out.println("常驻后台线程的资源初始化~");

    }
}
View Code

实现CommandLineRunner接口

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("缓存预热~");
        System.out.println("DB连接~");
        System.out.println("日志系统初始化~");
        System.out.println("资源文件初始化~");
        System.out.println("常驻后台线程的资源初始化~");
    }
}
View Code

2、监听spring事件ApplicationListener<>

ApplicationContext事件的实现机制是观察者模式,通过两个接口ApplicationEvent和ApplicationListener来实现。

spring容器在初始化时,会在不同的阶段,发布ApplicationEvent事件,因此,可以通过ApplicationListener监听各个阶段的事件来实现不同的功能。

spring提供了以下ApplicationEvent事件:

ContextStartedEvent 上下文启动事件

    此Start事件是当Spring容器启动时发布,即调用start() 方法时执行,意味着所有Lifecyc Bean 都监听到了 start 事件。

ContextRefreshedEvent 上下文刷新事件

    此 Refreshed 事件是当容器实例化时发布,即执行 refresh() 方法,此时所有的 Bean 都已加载,后置处理器被激活,容器中所有的对象都可以使用,如           果容器支持热重载,则 refresh 可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持)。

ContextStoppedEvent  上下文停止事件 

    当使用ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。

ContextClosedEvent 上下文关闭事件 

    当使用ConfigurableApplicationContext接口中的close() 方法关闭ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不          能被刷新或重启。

RequestHandledEvent 请求处理完成事件 

    此Request handled事件只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布。 

springboot提供的事件SpringApplicationEvent:

ApplicationStartingEvent SpringApplication启动事件

SpringBoot启动时发布该事件,其发布时机在环境变量Environment或容器ApplicationContext创建前但在注册ApplicationListener具体监听器之后。

ApplicationEnvironmentPreparedEvent 环境准备好事件

        ApplicationEnvironmentPreparedEvent事件多了一个environment属性,作用是利用事件发布订阅机制,相应监听器可以从ApplicationEnvironmentPreparedEvent事件中取出environment变量,然后可以为environment属性增加属性值或读出environment变量中的值。像ConfigFileApplicationListener监听器就是监听了ApplicationEnvironmentPreparedEvent事件,然后取出ApplicationEnvironmentPreparedEvent事件的environment属性,然后再为environment属性增加application.properties配置文件中的环境变量值。

        当SpringApplication已经开始启动且环境变量Environment已经创建后,并且为环境变量Environment配置了命令行和Servlet等类型的环境变量后,此时会发布ApplicationEnvironmentPreparedEvent事件。监听ApplicationEnvironmentPreparedEvent事件的第一个监听器是ConfigFileApplicationListener,因为是ConfigFileApplicationListener监听器还要为环境变量Environment增加application.properties配置文件中的环境变量;此后还有一些也是监听ApplicationEnvironmentPreparedEvent事件的其他监听器监听到此事件时,此时可以说环境变量Environment几乎已经完全准备好了。

ApplicationContextInitializedEvent  ApplicationContext容器初始化事件

         ApplicationContextInitializedEvent事件多了个ConfigurableApplicationContext类型的context属性,context属性的作用同样是为了相应监听器可以拿到这个context属性执行一些逻辑。

         ApplicationContextInitializedEvent事件在ApplicationContext容器创建后,且为ApplicationContext容器设置了environment变量和执行了ApplicationContextInitializers的初始化方法后但在bean定义加载前触发,标志ApplicationContext已经初始化完毕。

        ApplicationContextInitializedEvent是在为context容器配置environment变量后触发,此时ApplicationContextInitializedEvent等事件只要有context容器的话,那么其他需要environment环境变量的监听器只需要从context中取出environment变量即可,从而ApplicationContextInitializedEvent等事件没必要再配置environment属性。

ApplicationPreparedEvent ApplicationContext 容器准备好事件

           ApplicationPreparedEvent事件多了个ConfigurableApplicationContext类型的context属性,多了context属性的作用是能让监听该事件的监听器能拿到context属性,监听器拿到context属性一般有如下作用:

从事件中取出context属性,然后可以增加一些后置处理器,比如ConfigFileApplicationListener监听器监听到ApplicationPreparedEvent事件后,然后取出context变量,通过context变量增加了PropertySourceOrderingPostProcessor这个后置处理器;

       通过context属性取出beanFactory容器,然后注册一些bean,比如LoggingApplicationListener监听器通过ApplicationPreparedEvent事件的context属性取出beanFactory容器,然后注册了springBootLoggingSystem这个单例bean;

        通过context属性取出Environment环境变量,然后就可以操作环境变量,比如PropertiesMigrationListener。

        ApplicationPreparedEvent事件在ApplicationContext容器已经完全准备好时但在容器刷新前触发,在这个阶段bean定义已经加载完毕还有environment已经准备好可以用了。

ApplicationStartedEvent 应用开始事件

        ApplicationStartedEvent事件将在容器刷新后但ApplicationRunner和CommandLineRunner的run方法执行前触发,标志Spring容器已经刷新,此时容器已经准备完毕了。

        ApplicationRunner和CommandLineRunner接口有啥作用呢?我们一般会在Spring容器刷新完毕后,此时可能有一些系统参数等静态数据需要加载,此时我们就可以实现了ApplicationRunner或CommandLineRunner接口来实现静态数据的加载。

ApplicationReadyEvent 应用准备好事件

ApplicationReadyEvent事件在调用完ApplicationRunner和CommandLineRunner的run方法后触发,此时标志SpringApplication已经正在运行。

ApplicationFailedEvent 容器启动失败事件

       可以看到ApplicationFailedEvent事件除了多了一个context属性外,还多了一个Throwable类型的exception属性用来记录SpringBoot启动失败时的异常。

ApplicationFailedEvent事件在SpringBoot启动失败时触发,标志SpringBoot启动失败。

基于以上事件类型,我们可以监听ContextRefreshedEvent事件,初始化系统资源,以及监听ContextStoppedEvent事件来清理资源。

初始化资源:

@Component
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("做一些初始化的工作,比如缓存预热~");
        ApplicationContext ct= event.getApplicationContext();
        System.out.println(ct);
    }
}
View Code

清理资源:

@Component
public class MyApplicationStopListener implements ApplicationListener<ContextStoppedEvent> {
    @Override
    public void onApplicationEvent(ContextStoppedEvent event) {
        System.out.println("做一些清理资源的工作,比如缓存清理,DB连接清理~");
        ApplicationContext ct= event.getApplicationContext();
        System.out.println(ct);
    }

    @Override
    public boolean supportsAsyncExecution() {
        return ApplicationListener.super.supportsAsyncExecution();
    }
}
View Code

3、@PostConstruct、@PreDestroy注解

@PostConstruct注解时针对Bean初始化完成后,要执行的方法,@PreDestroy注解时Bean销毁时执行。

@Component
public class RedisInit {
    @PostConstruct
    public void init(){
        System.out.println("缓存预热~");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("缓存清理~");
    }
}
View Code

 

4、InitializingBean、DisposableBean接口

InitializingBean、DisposableBean 接口也是针对的Bean的。

@Component
public class RedisInitializingBean implements InitializingBean, DisposableBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("缓存预热~");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("缓存清理~");
    }
}
View Code

5、配置Bean时,指定Bean的init和destroy方法

@Bean(name = "redisInit",initMethod = "init",destroyMethod = "")
    public RedisInit redisInit(){
        return new RedisInit();
    }
View Code

 6、SmartLifecycle接口

SmartLifecycle接口有三个方法start  stop  isRuning,可以在start方法里初始化资源,在stop方法里实现资源清理

@Component
public class RedisSmartLifecycle implements SmartLifecycle {
    private boolean running = false;
    @Override
    public void start() {
        System.out.println("缓存预热~");
        running=true;
    }

    @Override
    public void stop() {
        System.out.println("缓存清理~");
        running=false;
    }

    @Override
    public boolean isRunning() {
        return running;
    }
}
View Code

 

posted on 2024-09-23 14:34  不知鱼  阅读(122)  评论(0编辑  收藏  举报