ApplicationRunner 是 SpringBoot 的特性。

一、使用场景🤪

当 SpringBoot 项目启动完成之后,如果我们想让程序自动执行相关业务代码的时候,我们可以使用 SpringBoot 提供调的接口ApplicationRunner。该接口中,只有一个run方法,他执行的时机是:Spring容器启动完成之后,就会紧接着执行这个接口实现类的run方法。

二、实践演示😜

根据如下代码所示,有以下几点需要注意:

  • 定义一个类实现ApplicationRunner接口
  • 使用@Component标记,使自定义的类成为 SpringBean
  • 添加@Order注解标记执行顺序(当Spring容器中包含多个ApplicationRunner实例时生效)

    1. @Order(10)
    2. @Component
    3. public class ConfigSvcRunner implements ApplicationRunner {
    4. @Override
    5. public void run(ApplicationArguments args) throws Exception {
    6. //你需要执行的相关业务代码
    7. }
    8. }

    三、总结和说明🤯

  • 自定义的类必须要注入到 Spring 容器中

  • 在一个项目中,可以定义多个ApplicationRunner的实现类,他们的执行顺序通过注解@Order或者再实现Ordered接口来实现。
  • run()的参数:ApplicationArguments可以获取到当前项目执行的命令参数(比如把这个项目打成 jar 执行的时候,带的参数可以通过ApplicationArguments获取到)。
  • 由于该方法是在容器启动完成之后才执行的,所以,这里可以从 Spring 容器中拿到其他已经注入的 Bean。

    四、自定义 Nacos 的配置类🤞

    ```java @Order(10) @Component public class ConfigSvcRunner implements ApplicationRunner {

    @Autowired private ApplicationContext applicationContext;

  1. @Override
  2. public void run(ApplicationArguments args) throws Exception {
  3. //使用ApplicationContext根据类型获取Spring容器中实现了ConfigSvcListener接口的Bean
  4. Map<String, ConfigSvcListener> beansOfType = applicationContext.getBeansOfType(ConfigSvcListener.class);
  5. //调用每个Bean的onMessage方法,该方法的作用是为其每个类注册监听器
  6. if (MapUtils.isNotEmpty(beansOfType)) {
  7. beansOfType.forEach((k, v) -> v.onMessage());
  8. }
  9. }

}

public abstract class ConfigSvcListener { private final Logger logger = LoggerFactory.getLogger(getClass());

public void onMessage() {
    String dataId = getConfigFile();
    String group = getDefaultGroup();
    Properties properties = new Properties();
    properties.put("serverAddr", getServerAddr());
    ConfigService configService = null;
    try {
        configService = NacosFactory.createConfigService(properties);
    } catch (NacosException e) {
        logger.error(e.getMessage(), e);
    }
    String content = null;
    try {
        content = configService.getConfig(dataId, group, 5000);
    } catch (NacosException e) {
        logger.error(e.getMessage(), e);
    }

    //logger.info("load {} success, content is {}", getConfigFile(), content);

    //初始化配置
    initCfg(getConfigFile(), content);

    try {
        configService.addListener(dataId, group, new Listener() {
            @Override
            public void receiveConfigInfo(String content) {
                //logger.info("receive {} success, content is {}", getConfigFile(), content);

                //更新配置
                refreshCfg(getConfigFile(), content);
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });
    } catch (NacosException e) {
        logger.error(e.getMessage(), e);
    }
}

protected abstract String getServerAddr();

protected abstract String getDefaultGroup();

protected abstract String getConfigFile();

protected abstract void initCfg(String config, String content);

protected abstract void refreshCfg(String config, String content);

} ```