SpringBoot 啟動(dòng)時(shí)執(zhí)行某些操作的九種方式
前言
在真實(shí)項(xiàng)目開(kāi)發(fā)過(guò)程中,我們經(jīng)常會(huì)需要在程序啟動(dòng)時(shí)執(zhí)行一些特定的業(yè)務(wù)操作,比如系統(tǒng)預(yù)熱、系統(tǒng)初始化等。小編為大家介紹 9 種實(shí)現(xiàn)方式。
實(shí)現(xiàn)方案
一、ApplicationRunner
1. 執(zhí)行時(shí)機(jī)
SpringBoot 應(yīng)用完全啟動(dòng)后。
2. 核心特點(diǎn)
實(shí)現(xiàn) ApplicationRunner 接口,通過(guò) ApplicationArguments 對(duì)象訪問(wèn)參數(shù),可以更方便地解析命令行參數(shù)(例如獲取--key=value形式的參數(shù)值)。
如果定義了多個(gè)Runner,可以使用 @Order 注解來(lái)控制他們的執(zhí)行順序,數(shù)值越小優(yōu)先級(jí)越高。
3. 代碼示例
@Component
@Order(1) // 執(zhí)行順序,可選
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// 這里寫(xiě)你的啟動(dòng)執(zhí)行邏輯,例如初始化緩存
// args 可以訪問(wèn)應(yīng)用參數(shù)
}
}二、CommandLineRunner
1. 執(zhí)行時(shí)機(jī)
SpringBoot 應(yīng)用完全啟動(dòng)后。
2. 核心特點(diǎn)
實(shí)現(xiàn) CommandLineRunner 接口,通過(guò) String... args 直接訪問(wèn)命令行原始參數(shù)數(shù)組。
如果定義了多個(gè)Runner,可以使用 @Order 注解來(lái)控制他們的執(zhí)行順序,數(shù)值越小優(yōu)先級(jí)越高。
3. 代碼示例
@Component
@Order(2) // 執(zhí)行順序,可選
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 這里寫(xiě)你的啟動(dòng)執(zhí)行邏輯
// args 可以訪問(wèn)命令行原始參數(shù)
}
}三、@PostConstruct 注解
1. 執(zhí)行時(shí)機(jī)
Bean 初始化時(shí),在對(duì)象依賴注入完成后執(zhí)行。
2. 核心特點(diǎn)
注解在方法上,使用簡(jiǎn)單。
此時(shí) Spring 容器可能還未完全初始化完畢,部分 Bean 可能尚未就緒,需注意可能的依賴問(wèn)題。
3. 代碼示例
@Component
public class MyInitBean {
@Autowired
private SomeRepository repository; // 假設(shè)的倉(cāng)庫(kù)類(lèi),用于數(shù)據(jù)訪問(wèn)
@PostConstruct
public void init() {
// 例如,在項(xiàng)目啟動(dòng)時(shí)從數(shù)據(jù)庫(kù)加載數(shù)據(jù)到靜態(tài)變量
List<SomeData> data = repository.findAll();
// ... 其他處理邏輯
}
}四、實(shí)現(xiàn) InitializingBean 接口
1. 執(zhí)行時(shí)機(jī)
Bean 的全部屬性被設(shè)置之后執(zhí)行。
2. 核心特點(diǎn)
實(shí)現(xiàn)接口的 afterPropertiesSet 方法。
與 @PostConstruct 類(lèi)似,都是 Bean 生命周期中的初始化方法。
3. 代碼示例
@Component
public class MyInitializingBean implements InitializingBean {
@Autowired
private SomeDependency dependency;
@Override
public void afterPropertiesSet() throws Exception {
// 確保屬性dependency注入后,再執(zhí)行初始化
// 你的初始化邏輯
}
}五、實(shí)現(xiàn) InitializingBean 接口
1. 執(zhí)行時(shí)機(jī)
Bean 的全部屬性被設(shè)置之后執(zhí)行。
2. 核心特點(diǎn)
實(shí)現(xiàn)接口的 afterPropertiesSet 方法。
與 @PostConstruct 類(lèi)似,都是 Bean 生命周期中的初始化方法。
3. 代碼示例
@Component
public class MyInitializingBeanimplementsInitializingBean {
@Autowired
private SomeDependency dependency;
@Override
publicvoidafterPropertiesSet()throws Exception {
// 確保屬性dependency注入后,再執(zhí)行初始化
// 你的初始化邏輯
}
}六、實(shí)現(xiàn) BeanPostProcessor 接口
1. 執(zhí)行時(shí)機(jī)
在 Bean 的初始化前后執(zhí)行。
2. 核心特點(diǎn)
實(shí)現(xiàn)接口的 postProcessBeforeInitialization 與 postProcessAfterInitialization 方法。
這個(gè)接口會(huì)影響所有的 bean 初始化。
3. 代碼示例
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 在初始化之前執(zhí)行的邏輯
System.out.println("Before Initialization: " + beanName);
return bean; // 返回bean本身或一個(gè)新的bean實(shí)例(可選)
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 在初始化之后執(zhí)行的邏輯
System.out.println("After Initialization: " + beanName);
return bean; // 返回bean本身或一個(gè)新的bean實(shí)例(可選)
}
}七、實(shí)現(xiàn) BeanFactoryPostProcessor 接口
1. 執(zhí)行時(shí)機(jī)
在 Spring 容器初始化時(shí)執(zhí)行,此時(shí)容器中所有的 Bean 定義已經(jīng)加載完,但是 Bean 的實(shí)例還未創(chuàng)建。
2. 核心特點(diǎn)
實(shí)現(xiàn)接口的 postProcessBeanFactory 方法。
這個(gè)接口只會(huì)執(zhí)行一次,執(zhí)行時(shí)機(jī)早于 BeanPostProcessor 。
3. 代碼示例
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("******************** MyBeanFactoryPostProcessor#postProcessBeanFactory ****************");
System.out.println("******************** bean的數(shù)量:[{}] ****************", beanFactory.getBeanDefinitionCount());
BeanDefinition userBeanDef = beanFactory.getBeanDefinition("student");
// 修改bean definition屬性信息
}
}八、實(shí)現(xiàn) ServletContextListener 接口
1. 執(zhí)行時(shí)機(jī)
Web 應(yīng)用啟動(dòng)初期,在初始化任何過(guò)濾器或 Servlet 時(shí)或者銷(xiāo)毀 Web 容器時(shí)執(zhí)行。
2. 核心特點(diǎn)
實(shí)現(xiàn)接口的 contextInitialized 和 contextDestroyed 方法。
適用于 Web 環(huán)境,監(jiān)聽(tīng) Servlet 上下文。
3. 代碼示例
@Component
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 在這里寫(xiě)Web應(yīng)用啟動(dòng)時(shí)的邏輯
// 例如,初始化一些Web應(yīng)用級(jí)別的資源
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 在這里寫(xiě)Web應(yīng)用關(guān)閉時(shí)的清理邏輯
}
}九、static 靜態(tài)代碼塊
1. 執(zhí)行時(shí)機(jī)
類(lèi)被加載時(shí)執(zhí)行。
2. 核心特點(diǎn)
僅僅是類(lèi)被加載時(shí),Bean 還未被創(chuàng)建。
3. 代碼示例
@Component
public class MyClass {
static {
System.out.println("執(zhí)行靜態(tài)代碼塊")
}
}



























