springboot2啟動(dòng)時(shí)執(zhí)行,初始化(或定時(shí)任務(wù))servletContext問(wèn)題
springboot2啟動(dòng)時(shí)執(zhí)行,初始化(或定時(shí)任務(wù))servletContext
需求:springboot 啟動(dòng)后自動(dòng)執(zhí)行,初始化數(shù)據(jù),并將數(shù)據(jù)放到 servletContext 中。
首先,不可使用 ServletContextListener 即不能用 @WebListener ,因?yàn)?servlet 容器初始化后,spring 并未初始化完畢,不能使用 @Autowired 注入 spring 的對(duì)象。
代碼如下:
可以實(shí)現(xiàn) ApplicationListener
@Component public class SettingDataInitListener implements ApplicationListener<ContextRefreshedEvent> { ? ? @Override ? ? public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { ? ? ? ? WebApplicationContext webApplicationContext =? ? ? ? ? ? ? (WebApplicationContext)contextRefreshedEvent.getApplicationContext(); ? ? ? ? ServletContext servletContext = webApplicationContext.getServletContext(); ? ? ? ? servletContext.setAttribute("key", "value"); ? ? } }
使用注解注入
service
類里注入 servletContext
@Autowired private ServletContext servletContext;
service
類里要啟動(dòng)執(zhí)行的方法加上注解
@PostConstruct
在定時(shí)任務(wù)里,也可以注入 servletContext,進(jìn)行定時(shí)操作
@Component public class MyTask { ? ? @Autowired ? ? private ServletContext servletContext; ? ? // 秒 分 時(shí) 日 月 周 ? ? @Scheduled(cron = "0 * * * * *") ? ? public void resetDays() { ? ? ? ? // servletContext ? ? } }
springboot啟動(dòng)時(shí)初始化數(shù)據(jù)的幾種方式
在我們用springboot搭建項(xiàng)目的時(shí)候,經(jīng)常碰到在項(xiàng)目啟動(dòng)時(shí)初始化一些字典數(shù)據(jù)、地市數(shù)據(jù)、等各類需求,針對(duì)這種需求Spring與Spring boot為我們提供了以下幾種方案供我們選擇:
- springboot提供的ApplicationRunner與CommandLineRunner接口
- Spring Bean初始化的init-method、PostConstruct注解、
InitializingBean、BeanPostProcessor接口
Spring的事件機(jī)制: 實(shí)現(xiàn) ApplicationListener 接口
一、ApplicationRunner與CommandLineRunner
如果需要在SpringApplication啟動(dòng)時(shí)執(zhí)行一些特殊的代碼,可以通過(guò)實(shí)現(xiàn)ApplicationRunner或CommandLineRunner接口,這兩個(gè)接口都提供單一的run方法,且run方法僅在SpringApplication.run(…)完成之前調(diào)用。
區(qū)別:參數(shù)不一樣,CommandLineRunner的參數(shù)是最原始的參數(shù),沒(méi)有進(jìn)行任何處理,ApplicationRunner的參數(shù)是ApplicationArguments
ApplicationRunner接口只需要自己創(chuàng)建類實(shí)現(xiàn)ApplicationRunner接口
/** ?* @author 重慶阿湯哥 ?* @Description: 測(cè)試 ?* @date 2021/11/26 ? ?*/ @Component @Slf4j public class ApplicationRunnerTest implements ApplicationRunner { ? ? @Override ? ? public void run(ApplicationArguments args) throws Exception { ? ? ? ? log.info("ApplicationRunner init data....."); ? ? } }
CommandLineRunner
對(duì)于這個(gè)接口而言,我們可以通過(guò)Order注解或者使用Ordered接口來(lái)指定調(diào)用順序,@Order()中的值越小,優(yōu)先級(jí)越高
/** ?* @author 重慶阿湯哥 ?* @Description: 測(cè)試 ?* @date 2021/11/26 ? ?*/ @Component @Slf4j @Order(1) public class CommandLineRunnerTest implements CommandLineRunner { ? ? @Override ? ? public void run(String... args) throws Exception { ? ? ? ? log.info("CommandLineRunner init data....."); ? ? } }
二、Spring Bean初始化的InitializingBean,init-method和PostConstruct
InitializingBean接口、BeanPostProcessor接口
InitializingBean接口為bean提供了初始化方法的方式,它只包括afterPropertiesSet()方法。
在spring初始化bean的時(shí)候,如果bean實(shí)現(xiàn)了InitializingBean接口,在對(duì)象的所有屬性被初始化后之后才會(huì)調(diào)用afterPropertiesSet()方法
/** ?* @author 重慶阿湯哥 ?* @Description: 測(cè)試 ?* @date 2021/11/26 ? ?*/ @Component @Slf4j @Component public class InitialingzingBeanTest implements InitializingBean { ? ? @Override ? ? public void afterPropertiesSet() throws Exception { ? ? ? ?log.info("InitializingBean init...."); ? ? } }
@PostConstruct
/** ?* @author 重慶阿湯哥 ?* @Description: 測(cè)試 ?* @date 2021/11/26 ? ?*/ @Component @Slf4j public class DynamicRouteMonitor { ? ? ? ? @PostConstruct ? ? public void init() { ? ? ? ? log.info("gateway route init..."); ? ? ? ? } }
BeanPostProcessor接口
可以用于判斷某些特定類加載完成后才能初始化數(shù)據(jù)的場(chǎng)景,只需要自己實(shí)現(xiàn)該接口中的方法進(jìn)行前置條件判斷
public interface BeanPostProcessor { ? ? @Nullable ? ? default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { ? ? ? ? return bean; ? ? } ? ? @Nullable ? ? default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { ? ? ? ? return bean; ? ? } }
三、Spring的事件機(jī)制
在Spring中,默認(rèn)對(duì)ApplicationEvent事件提供了如下支持:
ContextStartedEvent
:ApplicationContext啟動(dòng)后觸發(fā)的事件ContextStoppedEvent
:ApplicationContext停止后觸發(fā)的事件ContextRefreshedEvent
:ApplicationContext初始化或刷新完成后觸發(fā)的事件;也就是容器初始化完成后調(diào)用。ContextClosedEvent
:ApplicationContext關(guān)閉后觸發(fā)的事件;如web容器關(guān)閉時(shí)自動(dòng)會(huì)觸發(fā)spring容器的關(guān)閉。甚至大家聽(tīng)說(shuō)過(guò)的鉤子程序都是調(diào)用ctx.registerShutdownHook()進(jìn)行注冊(cè)虛擬機(jī)關(guān)閉。
利用ContextRefreshedEvent事件進(jìn)行初始化操作
/** ?* @author 重慶阿湯哥 ?* @Description:容器初始化完整后初始字典數(shù)據(jù) ?* @date 2021/11/26 ?10:51 ?*/ @Component public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent> { ? ? public void onApplicationEvent(ContextRefreshedEvent event) { ? ? ? ? //在容器加載完畢后獲取dao層來(lái)操作數(shù)據(jù)庫(kù) ? ? ? ? ISysDictTypeService sysDictTypeService = (ISysDictTypeService) event.getApplicationContext().getBean(ISysDictTypeService.class); ? ? ? ? sysDictTypeService.initDict(); ? ? ? ? IProvCityService provCityService = (IProvCityService) event.getApplicationContext().getBean(IProvCityService.class); ? ? ? ? provCityService.initProvCity(); ? ? } ? ? @Override ? ? protected Object clone() throws CloneNotSupportedException { ? ? ? ? return super.clone(); ? ? } }
這幾種方式都可以滿足我們?nèi)粘i_(kāi)發(fā)的需求,針對(duì)具體場(chǎng)景使用對(duì)應(yīng)的方案,在微服務(wù)應(yīng)用中使用也較廣泛。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于如何搭建CAS服務(wù)并將CAS項(xiàng)目導(dǎo)入IDEA
這篇文章主要介紹了關(guān)于如何搭建CAS服務(wù)并將CAS項(xiàng)目導(dǎo)入IDEA的問(wèn)題,文中提供了詳細(xì)的圖文講解,需要的朋友可以參考下,如果有錯(cuò)誤的地方還請(qǐng)指正2023-03-03詳解Java動(dòng)態(tài)代理的實(shí)現(xiàn)及應(yīng)用
這篇文章主要介紹了詳解Java動(dòng)態(tài)代理的實(shí)現(xiàn)及應(yīng)用的相關(guān)資料,希望通過(guò)本文大家能理解掌握J(rèn)ava動(dòng)態(tài)代理的使用方法,需要的朋友可以參考下2017-09-09spring boot+spring cache實(shí)現(xiàn)兩級(jí)緩存(redis+caffeine)
這篇文章主要介紹了spring boot+spring cache實(shí)現(xiàn)兩級(jí)緩存(redis+caffeine),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02Spring6.x對(duì)調(diào)度和異步執(zhí)行的注解支持示例詳解
這篇文章主要為大家介紹了Spring6.x對(duì)調(diào)度和異步執(zhí)行的注解支持示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11如何實(shí)現(xiàn)Spring?Event(異步事件)
這篇文章主要介紹了如何實(shí)現(xiàn)Spring?Event(異步事件)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02詳解Spring中使用xml配置bean的細(xì)節(jié)
本篇文章主要介紹了Spring中使用xml配置bean的細(xì)節(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06