北京旅行社网站建设公司,没有有知道钓鱼网站在哪儿做,网站目的及功能定位,泉州企业网站制作哪家好场景
项目中#xff0c;经常需要在启动过程中初始化一些数据#xff0c;如从数据库读取一些配置初始化#xff0c;或从数据库读取一些热点数据到redis进行初始化缓存。
方式一:实现CommandLineRunner 接口重写run方法逻辑
CommandLineRunner是Spring提供的接口#xff0…场景
项目中经常需要在启动过程中初始化一些数据如从数据库读取一些配置初始化或从数据库读取一些热点数据到redis进行初始化缓存。
方式一:实现CommandLineRunner 接口重写run方法逻辑
CommandLineRunner是Spring提供的接口定义了一个run()方法用于执行初始化操作。
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;Component
public class InitConfigCommand implements CommandLineRunner {Overridepublic void run(String... args) throws Exception {System.out.println(CommandLineRunner:{}接口实现方式重写);}
}CommandLineRunner的执行时机为Spring beans初始化之后因此CommandLineRunner的执行一定是晚于PostConstruct的。 若有多组初始化操作则每一组操作都要定义一个CommandLineRunner派生类并实现run()方法。这些操作的执行顺序使用Order(n)来设置n为int型数据。
Component
Order(99)
public class CommandLineRunnerA implements CommandLineRunner {Overridepublic void run(String... args) throws Exception {System.out.println(初始化CommandLineRunnerA);}
}Component
Order(1)
public class CommandLineRunnerB implements CommandLineRunner {Overridepublic void run(String... args) throws Exception {System.out.println(初始化CommandLineRunnerB);}
}如上会先执行CommandLineRunnerB的run()再执行CommandLineRunnerA的run()。 Order(n)中的n较小的会先执行较大的后执行。n只要是int值即可无需顺序递增。
方式二:实现ApplicationRunner接口重写run方法逻辑
ApplicationRunner接口与CommandLineRunner接口类似都需要实现run()方法。二者的区别在于run()方法的参数不同
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;Component
public class InitConfig implements ApplicationRunner {Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println(项目启动初始化);}
}ApplicationRunner接口的run()参数为ApplicationArguments对象因此可以获取更多项目相关的内容。 ApplicationRunner接口与CommandLineRunner接口的调用时机也是相同的都是Spring beans初始化之后。因此ApplicationRunner接口也使用Order(n)来设置执行顺序。
方式三:使用PostConstruct注解的方式
对于注入到Spring容器中的类在其成员函数前添加PostConstruct注解则在执行Spring beans初始化时就会执行该函数。
但由于该函数执行时其他Spring beans可能并未初始化完成因此在该函数中执行的初始化操作应当不依赖于其他Spring beans。
Component
public class Construct {PostConstructpublic void doConstruct() throws Exception {System.out.println(初始化PostConstruct);}
}初始化顺序
PostConstruct 注解方法CommandLineRunner接口实现ApplicationRunner接口实现
扩展
PostConstruct注解使用在方法上它可以被用来标注一个非静态的 void 方法这个方法会在该类被 Spring 容器初始化后立即执行。因为它的执行时机是在依赖注入之后对象构造完成之后也就是说是在Autowired注入之后执行。所以这里可以进行一些初始化操作如某些需要在对象创建后才能进行的数据初始化操作。
需要注意以下几点
PostConstruct 只能用在方法上面而不能用在属性或构造函数上。一个类中可以有多个使用 PostConstruct 注解的方法但执行顺序并不是固定的。PostConstruct 注解的方法在本类中必须是无参数的如果有参数那么这个方法不会被执行。PostConstruct 注解的方法在实现上可以使用任意修饰符。
假设我们有一个需要初始化数据的类
public class InitService {private ListString data;public InitService() {this.data Arrays.asList(A, B, C);}PostConstructpublic void init() {data.add(D);}public ListString getData() {return this.data;}
}当我们实例化 InitService 时构造函数会为 data 属性赋初值而 PostConstruct 注解的 init 方法会在 Spring 容器实例化完 InitService 后被执行将 “D” 添加到 data 列表中。所以当我们调用 getData() 方法时返回的列表应该是 [A, B, C, D]。
接下来看看 Autowired 和PostConstruct 的具体执行顺序
Service
public class TestA {static {System.out.println(staticA);}Autowiredprivate TestB testB;public TestA() {System.out.println(这是TestA 的构造方法);}PostConstructprivate void init() {System.out.println(这是TestA的 init 方法);testB.test();}
}Service
public class TestB {static {System.out.println(staticB);}PostConstructprivate void init() {System.out.println(这是TestB的init 方法);}public TestB() {System.out.println(这是TestB的构造方法);}void test() {System.out.println(这是TestB的test方法);}
}构造方法在对象初始化时执行。执行顺序在static静态代码块之后。
服务启动后输出结果如下
staticA
这是TestA 的构造方法
staticB
这是TestB的构造方法
这是TestB的init 方法
这是TestA的 init 方法
这是TestB的test方法结论为等Autowired注入后在执行PostConstruct注解的方法。
方式四:静态代码块
static静态代码块在类加载的时候即自动执行。
使用的static静态代码块实现原理为Component static代码块, spring boot项目在启动过程中会扫描Component 并初始化相应的类类的初始化过程会运行静态代码块。
Component
public class WordInitConfig {static {WordSegmenter.segWithStopWords(初始化分词);}
}所以得到结论
staticconstructerAutowiredPostConstructApplicationRunnerCommandLineRunner