进阶篇-SpringBoot2.x系统启动任务

1.本篇前言

在日常开发中,我们经常会遇到在项目启动阶段要做一些数据初始化等操作,并且只在项目启动时进行,后续不再执行。而在SpringBoot2.x中,可根据不同使用场景使用不同的方式去实现该功能。具体如下:

  • 实现CommandLineRunner接口
  • 实现ApplicationRunner接口
  • 实现ApplicationListener接口
  • 使用@PostConstruct 注解
  • 实现InitializingBean接口
  1. CommandLineRunnerApplicationRunner 接口是在容器启动成功后的最后一步回调(类似开机自启动)。区别在于接收的参数不一样。CommandLineRunner 的参数是最原始的参数,没有做任何处理。ApplicationRunner的参数是ApplicationArguments,是对原始参数做了进一步的封装。
  2. 使用ApplicationListener,定义一个 ServletContextListener,然后监听项目启动和销毁,在contextInitialized方式中编写初始化业务逻辑即可。
  3. 使用 @PostConstruct 注解同样可以帮助我们完成资源的初始化操作,前提是这些初始化操作不需要依赖于其它Spring beans的初始化工作。

启动任务常用场景:

  • 数据初始化
  • 初始化系统参数
  • 文件初始化
  • 缓存初始化

2.代码实现

2.1 基于 CommandLineRunner 实现

  1. 定义 InitCommandLineRunner 并且实现 CommandLineRunner 接口
  2. 首先通过 @Component 注解将 InitCommandLineRunner 注册为Spring容器中的一个 Bean。
  3. 添加 @Order 注解,表示这个启动任务的执行优先级,因为在一个项目中,启动任务可能有多个,所以需要有一个排序。@Order 注解中,数字越小,优先级越大,默认情况下,优先级的值为 Integer.MAX_VALUE,表示优先级最低。
  4. 在 run 方法中,编写启动任务的核心逻辑,当项目启动时,run方法会被自动执行。run 方法的参数,来自于项目的启动参数,即项目入口类中,main方法的参数会被传到这里
/**
 * 功能描述: CommandLineRunner实现启动任务
 * @author  TuYong
 * @date  2022/6/14 14:16
 */
@Component
@Order(100)
@Slf4j
public class InitCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("读取String数组参数初始化操作内容...");
    }
}

测试结果如下:
在 IDEA 中,可以通过如下方式来配置参数

启动项目后,我们可以看到启动过程中run方式被执行。

2.2 基于 ApplicationRunner 实现

代码如下,自定义类InitApplicationRunner实现 ApplicationRunner 接口即可。用法同CommandLineRunner一致,ApplicationRunner 可以接收更多类型的参数(ApplicationRunner 除了可以接收 CommandLineRunner 的参数之外,还可以接收 key/value 形式的参数)。具体获取参数方法如下:

  • args.getNonOptionArgs();用来获取命令行中的无key参数(和CommandLineRunner一样)。
  • args.getOptionNames();用来获取所有key/value形式的参数的key。
  • args.getOptionValues(key));根据key获取key/value 形式的参数的value。
  • args.getSourceArgs(); 获取命令行中的所有参数。
/**
 * 功能描述: ApplicationRunner实现启动任务
 * @author  TuYong
 * @date  2022/6/14 14:31
 */
@Component
@Order(99)
@Slf4j
public class InitApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        //获取命令行中的无key参数
        List nonOptionArgs = args.getNonOptionArgs();
        log.info("InitApplicationRunner无key参数:{}",nonOptionArgs);

        //获取所有key/value形式的参数的key
        Set optionNames = args.getOptionNames();
        for (String key : optionNames) {
            //根据key获取key/value 形式的参数的value
            log.info("InitApplicationRunner有key参数:{}",args.getOptionValues(key));
        }
        //获取命令行中的所有参数
        String[] sourceArgs = args.getSourceArgs();
        log.info("InitApplicationRunner所有参数:{}",Arrays.toString(sourceArgs));
    }
}

测试结果如下:
在 IDEA 中,可以通过如下方式来配置参数

启动项目,可以看到控制台打印如下:

2.3 基于 ApplicationListener 实现

定义义一个 ServletContextListener,在contextInitialized方法中进行数据初始化操作即可。

@Component
@Slf4j
public class InitServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //这里编写启动任务代码
        log.info("监听器初始化.....");
    }
}

测试结果如下:

2.4 基于@PostConstruct注解实现

示例代码如下,被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。
创建bean的时候执行顺序
Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)

需要注意的是:

  • 在spring创建bean的时候触发,此时容器还未完全初始化完毕,如果逻辑中引用了还未完成初始化的bean会导致异常 ,所以需要考虑加载顺序
  • 如果@PostConstruct方法内的逻辑处理时间较长,就会增加SpringBoot应用初始化Bean的时间,进而增加应用启动的时间。因为只有在Bean初始化完成后,SpringBoot应用才会打开端口提供服务,所以在此之前,应用不可访问
/**
 * 功能描述: 基于@PostConstruct实现启动任务
 * @author  TuYong
 * @date  2022/6/14 14:59
 */
@Service
@Slf4j
public class SysParamService {

    @PostConstruct
    public void initParam(){
        //编写业务逻辑代码,比如从数据库查询系统参数放入缓存中
        log.info("初始化系统参数......");
    }
}

测试结果如下

2.5 基于 InitializingBean 实现

示例代码如下:

/**
 * 功能描述: 基于InitializingBean实现启动任务
 * @author  TuYong
 * @date  2022/6/14 15:25
 */
@Component
@Slf4j
public class MyInitializingBean implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        //编写启动任务代码
        log.info("InitializingBean 执行初始化任务...");
    }
}

测试结果如下



发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章