springboot 之 项目启动后执行某方法

由于在工作中需要缓存省市区信息,并且还要定时的去更新,所以写了个定时任务去定时更新缓存的省市区信息,但是当服务器重启后缓存是为空的,这时使用会有问题,所以想到在项目启动是去初始化缓存信息,下面讲到的方法就是基于此而来。

第一个想到的是使用ApplicationRunnerCommandLineRunner,下面讲讲这两个实现方式

1、实现ApplicationRunner接口

ApplicationRunner 源码如下 :

public interface ApplicationRunner {

          void run(ApplicationArguments var1) throws Exception;
      }

2、实现CommandLineRunner接口

CommandLineRunner 源码如下:

public interface CommandLineRunner {

          void run(String... var1) throws Exception;
      }

对比:
    相同点:这两种方法提供的目的是为了满足,在项目启动的时候立刻执行某些方法。我们可以通过实现ApplicationRunner和CommandLineRunner,来实现,他们都是在SpringApplication 执行之后开始执行的。
    不同点:CommandLineRunner接口可以用来接收字符串数组的命令行参数,ApplicationRunner 是使用ApplicationArguments 用来接收参数的 【根据业务场景灵活运用】

代码示例:

/**
 * @description: 项目启动缓存省市信息
 * @author: 
 * @date: 2021/3/11 14:02
 */
@Component
@Order(value=1)
public class LocalCacheRunner implements CommandLineRunner {

    @Autowired
    private NewDistrictCustomManager newDistrictCustomManager;

    /**
     * Callback used to run the bean.
     *
     * @param args incoming main method arguments
     * @throws Exception on error
     */
    @Override
    public void run(String... args){
        try{
            List<ProvinceCityDistrictDto> cacheList = newDistrictCustomManager.queryAllPCDInfo();
            ProvinceCityDistrictLocalCache.setCache(cacheList);
        }catch (Exception e){

        }
    }
}
/**
 * @description: TODO
 * @author: 
 * @date: 2021/3/11 14:50
 */
 @Component
@Order(value=1)
public class LocalCacheRunner implements ApplicationRunner {

    @Autowired
    private NewDistrictCustomManager newDistrictCustomManager;

    /**
     * Callback used to run the bean.
     *
     * @param args incoming application arguments
     * @throws Exception on error
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        try{
            List<ProvinceCityDistrictDto> cacheList = newDistrictCustomManager.queryAllPCDInfo();
            ProvinceCityDistrictLocalCache.setCache(cacheList);
        }catch (Exception e){

        }
    }
}

3、虽然这样也可以实现我的需求,但是这样做需要新建一个类,这时想到另外一种方式:InitializingBean

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是实现该接口的类,在初始化bean的时候都会执行该方法。

代码示例:

/**
 * @Description: (省市区本地缓存管理器)
 */
@Slf4j
@Component
public class ProvinceCityDistrictLocalCacheJob extends SingleNodeOneQuerySaturnJob implements InitializingBean {
    private static final Logger logger = LoggerFactory.getLogger(ProvinceCityDistrictLocalCacheJob.class);

    @Autowired
    private NewDistrictCustomManager newDistrictCustomManager;

    /**
     * 单次循环执行方法
     */
    @Override
    public String execute() {
        List<ProvinceCityDistrictDto> cacheList = newDistrictCustomManager.queryAllPCDInfo();
        logger.info("省市区本地缓存size:{}", cacheList.size());
        ProvinceCityDistrictLocalCache.setCache(cacheList);
        return null;
    }

    /**
     * 在bean注册的时候执行,初始化省市区信息
     */
    @Override
    public void afterPropertiesSet() {
        List<ProvinceCityDistrictDto> cacheList = newDistrictCustomManager.queryAllPCDInfo();
        logger.info("省市区本地缓存size:{}", cacheList.size());
        ProvinceCityDistrictLocalCache.setCache(cacheList);
    }
}

由此直接在定时任务中实现InitializingBean 接口,然后重写afterPropertiesSet方法,就可以实现在加载bean的时候,就把省市区信息初始化进缓存了。

这里要注意:ProvinceCityDistrictLocalCacheJob 类必须要交给spring管理,这样才能在项目启动的时候加载bean,所以要加上@Component注解。

3、用spring时,在某个Class被初始化之后再执行一些代码,可以用@PostConstruct注解方法,如:

package org.dhframework;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component
public class Test4 {

    @PostConstruct
    public void pc1() {
        System.out.println("Test4.postConstruct()");
    }
}

@PostConstruct应用场景:
在生成对象时候做一些初始化操作,而这些初始化操作又依赖于依赖注入(populateBean),那么就无法在构造函数中实现。这时,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。

题外话:为何构造函数中无法使用依赖注入的属性呢?
因为在做doCreateBean时,大致的步骤是这样的:

  • 实例化bean,这里会调用构造方法
  • 填充属性,就是依赖注入
  • 初始化bean调用后置处理器,其中会执行@PostConstruct注解方法

优先级:
Constructor >> @Autowired >> @PostConstruct
执行bean的生命周期中的初始化回调方法,也就是InitializingBean接口的afterPropertiesSet()方法
那么,显然在构造方法执行的时候,属性填充还没有开始,所以 构造函数中无法使用依赖注入的属性

最后:这三种方式的执行顺序:

@PostConstruct>InitializingBean>ApplicationRunner

你可能感兴趣的:(spring,boot,/spring,cloud,spring,spring,boot,java)