一,前言
有时候,我们可能需要在使用一个service或者工具之前,做一些数据的初始化或者对象的初始化。这里介绍一下在开发中常用的三种做法
二,实战
2.1 使用 static 关键字
这个方法是比较普遍的实现方式之一,了解过类加载顺序的朋友都知道,静态属性和静态方法都比实例属性和实例方法先加载,这里就不多介绍了。
2.2 实现 CommandLineRunner 接口
在springboot中,我们可以实现CommandLineRunner接口,重写run()方法。
当springboot程序启动的时候,会自动地执行run方法,我们可以在这个run方法里边进行一些系统数据的初始化,例如:加载字典,设置缓存等等。
具体代码:
@Component
@Slf4j
public class InitCommon implements CommandLineRunner {
@Resource
private DictAspect dictAspect;
@Resource
private BaseYmlProperties baseYmlProperties;
@Override
public void run(String... args) {
log.info(">>>>>>>>>>>>>>> common init start <<<<<<<<<<<<<");
dictAspect.initCache();
UploadFileVO.setDomain(baseYmlProperties.getQiniuCdnProfile());
log.info(">>>>>>>>>>>>>>> common init end <<<<<<<<<<<<<");
}
}

当然,你还可以根据自己的业务需求,构建多个初始化工具。
如果有多个初始化工具,你可以使用@Order注解来指定他们的顺序,数值越小,优先级越高。
@Component
@Slf4j
@Order(1)
public class InitCommon implements CommandLineRunner {
@Resource
private DictAspect dictAspect;
@Resource
private BaseYmlProperties baseYmlProperties;
@Override
public void run(String... args) {
log.info(">>>>>>>>>>>>>>> common init start <<<<<<<<<<<<<");
dictAspect.initCache();
UploadFileVO.setDomain(baseYmlProperties.getQiniuCdnProfile());
log.info(">>>>>>>>>>>>>>> common init end <<<<<<<<<<<<<");
}
}
@Order(2)
@Component
class Demo1 implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("demo1 init...");
}
}
@Order(3)
@Component
class Demo2 implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("demo2 init...");
}
}

2.3 使用@PostConstruct注解
@PostConstruct注解的方法,会在构造方法之后执行;
加载顺序为:Constructor > @Autowired > @PostConstruct > 静态方法;
特点:
- 只有一个非静态方法能使用此注解
- 被注解的方法不得有任何参数
- 被注解的方法返回值必须为void
- 被注解方法不得抛出已检查异常
- 此方法只会被执行一次
@Component
@Slf4j
public class InitCommon implements CommandLineRunner {
@Resource
private DictAspect dictAspect;
@Resource
private BaseYmlProperties baseYmlProperties;
@PostConstruct
void init() {
System.out.println(" @PostConstruct ...");
System.out.println(dictAspect == null);
}
public InitCommon(){
System.out.println(" Constructor... ");
System.out.println(dictAspect == null);
}
@Override
public void run(String... args) {
log.info(">>>>>>>>>>>>>>> common init start <<<<<<<<<<<<<");
dictAspect.initCache();
UploadFileVO.setDomain(baseYmlProperties.getQiniuCdnProfile());
log.info(">>>>>>>>>>>>>>> common init end <<<<<<<<<<<<<");
}
}

可以看到,构造方法比@PostConstruct注解先直接,而且在构造方法执行的时候,注入的对象还是空的,当@PostConstruct注解执行的时候,注入的对象已经有值了。
2.4 实现InitializingBean接口,重写afterPropertiesSet()方法;
@Component
class TestInit implements InitializingBean {
@Resource
private DictAspect dictAspect;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(" afterPropertiesSet ...");
System.out.println(dictAspect == null);
}
@PostConstruct
void init() {
System.out.println(" @PostConstruct ...");
System.out.println(dictAspect == null);
}
public TestInit(){
System.out.println(" Constructor... ");
System.out.println(dictAspect == null);
}
}

可以看到,也是和@PostConstruct注解差不多的结果。只不过,@PostConstruct注解已经在jdk9中计划被删除了,后续的话,还是用InitializingBean接口比较靠谱一点。
三,总结
总的来说,在springboot中初始化数据的方式还是挺多的,我们可以根据自己实际的场景来选用,而且有一些初始化的方式也是有先后顺序的,如果在初始化的时候依赖其他的注入bean,可能就要注意了。
本文介绍了在Spring Boot中进行初始化的三种常见方法:1) 使用`static`关键字,静态属性和方法在类加载时初始化;2) 实现`CommandLineRunner`接口,在启动时执行`run()`方法进行数据初始化;3) 使用`@PostConstruct`注解,在构造方法之后执行,确保依赖注入已完成。同时提到了`InitializingBean`接口的`afterPropertiesSet()`方法作为备选,因为`@PostConstruct`在JDK9后可能被删除。
2919

被折叠的 条评论
为什么被折叠?



