原創不易,如需轉載,請註明出處https://www.cnblogs.com/baixianlong/p/11117665.html,謝謝支援哈!!!
一、問題
在平時的業務模組開發過程中,難免會需要做一些全域性的任務、快取、執行緒等等的初始化工作,那麼如何解決這個問題呢?方法有多種,但具體又要怎麼選擇呢?
二、資源初始化
1、既然要做資源的初始化,那麼就需要了解一下springboot啟動過程(這裡大體說下啟動過程,詳細:https://www.cnblogs.com/dennyzhangdd/p/8028950.html)
按照前面的分析,Spring-boot容器啟動流程總體可劃分為2部分:
- 執行註解:掃描指定範圍下的bean、載入自動配置類對應的bean載入到IOC容器。
- man方法中具體SpringAppliocation.run(),全流程貫穿SpringApplicationEvent(經典的spring事件驅動模型),有6個子類:
- ApplicationFailedEvent.class
- ApplicationPreparedEvent.class
- ApplicationReadyEvent.class
- ApplicationStartedEvent.class
- ApplicationStartingEvent.class
- SpringApplicationEvent.class
2、CommandLineRunner和ApplicationRunner
由上可知,我們只要實現這兩個中的任何一個介面便可以完成我們的資源初始化任務,可以看到它們的載入是在容器完全啟動之前。它兩的區別是:前者的run方法引數是String...args,直接傳入字串,後者的引數是ApplicationArguments,對引數進行了封裝。功能上是一樣的。同時也可以使用 @Order註解來實現資源載入的先後順序,值越小,優先順序越高。例項如下:
@Component
@Order(1)
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("...init resources by implements CommandLineRunner");
}
}
@Component
@Order(2)
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
System.out.println("...init resources by implements ApplicationRunner");
}
}
3、@PostConstruct
在具體Bean的例項化過程中執行,@PostConstruct註解的方法,會在構造方法之後執行,順序為Constructor > @Autowired > @PostConstruct > 靜態方法,所以這個註解就避免了一些需要在構造方法裡使用依賴元件的尷尬(與之對應的還有@PreDestroy,在物件消亡之前執行,原理差不多)。使用特點如下:
- 只有一個非靜態方法能使用此註解
- 被註解的方法不得有任何引數
- 被註解的方法返回值必須為void
- 被註解方法不得丟擲已檢查異常
此方法只會被執行一次
@Component public Class AAA { @Autowired private BBB b; public AAA() { System.out.println("此時b還未被注入: b = " + b); } @PostConstruct private void init() { System.out.println("此時b已經被注入: b = " + b); } }
4、InitializingBean
InitializingBean 是 Spring 提供的一個介面,只包含一個方法 afterPropertiesSet()。凡是實現了該介面的類,當其對應的 Bean 交由 Spring 管理後,當其必要的屬性全部設定完成後,Spring 會呼叫該 Bean 的 afterPropertiesSet()。在Bean在例項化的過程中執執行順序為:Constructor > @PostConstruct > InitializingBean > init-method
public class InitSequenceBean implements InitializingBean {
public InitSequenceBean() {
System.out.println("InitSequenceBean: constructor");
}
@PostConstruct
public void postConstruct() {
System.out.println("InitSequenceBean: postConstruct");
}
public void initMethod() {
System.out.println("InitSequenceBean: init-method");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitSequenceBean: afterPropertiesSet");
}
}
5、ApplicationListener
ApplicationListener 就是spring的監聽器,能夠用來監聽事件,典型的觀察者模式。如果容器中有一個ApplicationListener Bean,每當ApplicationContext釋出ApplicationEvent時,ApplicationListener Bean將自動被觸發。這種事件機制都必須需要程式顯示的觸發。其中spring有一些內建的事件,當完成某種操作時會發出某些事件動作。比如監聽ContextRefreshedEvent事件,當所有的bean都初始化完成並被成功裝載後會觸發該事件,實現ApplicationListener
@Component
public class DataSourceInitListener implements ApplicationListener<ContextRefreshedEvent> {//ContextRefreshedEvent為啟動事件
private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceInitListener.class);
@Autowired
private SystemConfigService systemConfigService;
@Autowired
private ItemService itemService;
@Autowired
private SystemResultService systemResultService;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(event.getApplicationContext().getParent() == null) {//判斷是否執行過,執行過則不再執行
LOGGER.info("初始化systemConfig資料");
systemConfigService.initConfig();
LOGGER.info("初始化返回訊息資料");
systemResultService.initResult();
LOGGER.info("系統初始化結束...........");
}
}
}
三、總結
- 到此一些資源初始化的方法就說的差不多了,其中不免有些錯誤的地方,或者理解有偏頗的地方歡迎大家提出來!
個人部落格地址:
segmentfault:https://segmentfault.com/u/baixianlong