本文介绍SpringBoot项目的四种启动后执行功能的方式。
-
方法1: ApplicationRunner 接口
java language-md-end-block">import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.***ponent;
@***ponent
@Order(value = 2)
public class ApplicationRunnerTest implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("========ApplicationRunner========");
// 失败后,服务停止
// throw new RuntimeException();
}
}
-
类需要实现
ApplicationRunner
接口,实现public void run(ApplicationArguments args) throws Exception
方法 -
类增加
@***ponent
注解成为spring可管理的bean -
多个
ApplicationRunner
实现类,可以通过@Order
注解指定执行顺序,数越小就越先执行 -
当
run
方法执行异常,则服务启动失败
-
方法2: ***mandLineRunner 接口
import org.springframework.boot.***mandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.***ponent;
@***ponent
@Order(value = 2)
public class ***mandLineRunnerTest implements ***mandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("========***mandLineRunner========");
// 失败后,服务停止
// throw new RuntimeException();
}
}
-
类需要实现
***mandLineRunner
接口,实现public void run(String... args) throws Exception
方法 -
类增加
@***ponent
注解成为spring可管理的bean -
多个
***mandLineRunner
实现类,可以通过@Order
注解指定执行顺序,数越小就越先执行 -
当
run
方法执行异常,则服务启动失败
-
方法3: @PostConstruct 注解
import javax.annotation.PostConstruct;
import org.springframework.stereotype.***ponent;
@***ponent
public class PostConstructTest {
@PostConstruct
public void init() {
System.out.println("========PostConstruct========");
// 失败后,服务停止
// throw new RuntimeException();
}
}
-
类增加
@***ponent
注解成为spring可管理的bean -
在需要执行的方法上,增加
@PostConstruct
注解,方法名称不一定是init -
当方法执行异常,则服务启动失败
-
多个方法标注
@***ponent
注解,按照顺序依次执行,即使方法上标注@Order
注解。
import javax.annotation.PostConstruct;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.***ponent;
@***ponent
public class PostConstructTest {
@PostConstruct
@Order(value = 2)
public void init() {
System.out.println("========PostConstruct========");
}
@PostConstruct
@Order(value = 1)
public void init2() {
System.out.println("========PostConstruct2========");
}
}
虽然将两个方法上都加了@Order
注解,并且init2()
方法的设置顺序小于init()
方法,但是仍然先执行init()
方法
-
方法4: ApplicationListener 接口
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.***ponent;
@***ponent
public class ApplicationListenerTest implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("========ApplicationListener========");
// 失败后,服务停止
// throw new RuntimeException();
}
}
-
类需要实现
ApplicationListener
接口,实现public void onApplicationEvent(E event)
方法 -
类增加
@***ponent
注解成为spring可管理的bean -
多个
***mandLineRunner
实现类,可以通过@Order
注解指定执行顺序,数越小就越先执行 -
当
onApplicationEvent
方法执行异常,则服务启动失败 -
当
onApplicationEvent
方法采用异步执行时,方法执行异常,服务启动不会失败
-
四种方式比较
-
@PostConstruct
注解在类被加载的时候执行,而ApplicationRunner
、***mandLineRunner
接口是在工程启动后才执行 -
ApplicationListener
接口执行顺序晚于@PostConstruct
注解,早于ApplicationRunner
、***mandLineRunner
接口 -
四种方式在执行方法时,只要失败,服务均不能启动
-
ApplicationRunner
、***mandLineRunner
接口同时存在时,通过指定@Order
注解可以改变总体的自行顺序,并不是哪个接口一定先执行 -
无
@Order
注解或者@Order
注解的顺序一致时,ApplicationRunner
、***mandLineRunner
接口同时存在时,则ApplicationRunner
接口优先执行 -
注 由于
ApplicationListener
接口是基于发布订阅模式的,因此可以支持异步执行,异步执行时,ApplicationListener
接口早于ApplicationRunner
、***mandLineRunner
接口执行,但不是等到ApplicationListener
接口执行完成后才执行ApplicationRunner
、***mandLineRunner
接口
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.***ponent;
@***ponent
public class ApplicationListenerTest implements ApplicationListener<ContextRefreshedEvent>{
@Override
@Async // 已经在SpringBoot启动类增加了@EnableAsync注解
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("========ApplicationListener========");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 由于异步执行,所以方法执行失败后,仍然不会停止服务
// throw new RuntimeException();
}
}
-
其他
-
对于
@Order
注解,也可以采用Ordered
接口来实现,需要实现public int getOrder()
方法
@***ponent
//@Order(value = 2)
public class ***mandLineRunnerTest implements ***mandLineRunner ,Ordered {
@Override
public int getOrder() {
return 1;
}
@Override
public void run(String... args) throws Exception {
System.out.println("========***mandLineRunner========");
// 失败后,服务停止
// throw new RuntimeException();
}
}
-
ApplicationListener 扩展方式
由于ApplicationListener 是发布订阅模式,可以直接采用@EventListener
注解来实现。
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.***ponent;
@***ponent
public class EventListenerTest {
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("========EventListener========");
// 失败后,服务停止
// throw new RuntimeException();
}
}