由于在工作中需要缓存省市区信息,并且还要定时的去更新,所以写了个定时任务去定时更新缓存的省市区信息,但是当服务器重启后缓存是为空的,这时使用会有问题,所以想到在项目启动是去初始化缓存信息,下面讲到的方法就是基于此而来。
第一个想到的是使用ApplicationRunner和CommandLineRunner,下面讲讲这两个实现方式
ApplicationRunner 源码如下 :
public interface ApplicationRunner {
void run(ApplicationArguments var1) throws Exception;
}
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){
}
}
}
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注解。
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时,大致的步骤是这样的:
优先级:
Constructor >> @Autowired >> @PostConstruct
执行bean的生命周期中的初始化回调方法,也就是InitializingBean接口的afterPropertiesSet()方法
那么,显然在构造方法执行的时候,属性填充还没有开始,所以 构造函数中无法使用依赖注入的属性
最后:这三种方式的执行顺序:
@PostConstruct>InitializingBean>ApplicationRunner