SpringBoot中資源初始化加載的幾種方式

一、問題

在平時(shí)的業(yè)務(wù)模塊開發(fā)過程中,難免會(huì)需要做一些全局的任務(wù)、緩存、線程等等的初始化工作,那么如何解決這個(gè)問題呢?方法有多種,但具體又要怎么選擇呢?

二、資源初始化

1.既然要做資源的初始化,那么就需要了解一下springboot啟動(dòng)過程(這里大體說(shuō)下啟動(dòng)過程,詳細(xì):https://www.cnblogs.com/dennyzhangdd/p/8028950.html
image.png

按照前面的分析,Spring-boot容器啟動(dòng)流程總體可劃分為2部分:

執(zhí)行注解:掃描指定范圍下的bean、載入自動(dòng)配置類對(duì)應(yīng)的bean加載到IOC容器。
man方法中具體SpringAppliocation.run(),全流程貫穿SpringApplicationEvent(經(jīng)典的spring事件驅(qū)動(dòng)模型),有6個(gè)子類:
  • ApplicationFailedEvent.class
  • ApplicationPreparedEvent.class
  • ApplicationReadyEvent.class
  • ApplicationStartedEvent.class
  • ApplicationStartingEvent.class
  • SpringApplicationEvent.class
2、CommandLineRunner和ApplicationRunner

由上可知,我們只要實(shí)現(xiàn)這兩個(gè)中的任何一個(gè)接口便可以完成我們的資源初始化任務(wù),可以看到它們的加載是在容器完全啟動(dòng)之前。它兩的區(qū)別是:前者的run方法參數(shù)是String...args,直接傳入字符串,后者的參數(shù)是ApplicationArguments,對(duì)參數(shù)進(jìn)行了封裝。功能上是一樣的。同時(shí)也可以使用 @Order注解來(lái)實(shí)現(xiàn)資源加載的先后順序,值越小,優(yōu)先級(jí)越高。實(shí)例如下:

@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的實(shí)例化過程中執(zhí)行,@PostConstruct注解的方法,會(huì)在構(gòu)造方法之后執(zhí)行,順序?yàn)镃onstructor > @Autowired > @PostConstruct > 靜態(tài)方法,所以這個(gè)注解就避免了一些需要在構(gòu)造方法里使用依賴組件的尷尬(與之對(duì)應(yīng)的還有@PreDestroy,在對(duì)象消亡之前執(zhí)行,原理差不多)。使用特點(diǎn)如下:

  • 只有一個(gè)非靜態(tài)方法能使用此注解
  • 被注解的方法不得有任何參數(shù)
  • 被注解的方法返回值必須為void
  • 被注解方法不得拋出已檢查異常
  • 此方法只會(huì)被執(zhí)行一次
@Component
public Class AAA {    
    @Autowired    
    private BBB b;   

    public AAA() {        
        System.out.println("此時(shí)b還未被注入: b = " + b);    
    }    
    @PostConstruct    
    private void init() {        
        System.out.println("此時(shí)b已經(jīng)被注入: b = " + b);    
    }
}
4、InitializingBean

InitializingBean 是 Spring 提供的一個(gè)接口,只包含一個(gè)方法 afterPropertiesSet()。凡是實(shí)現(xiàn)了該接口的類,當(dāng)其對(duì)應(yīng)的 Bean 交由 Spring 管理后,當(dāng)其必要的屬性全部設(shè)置完成后,Spring 會(huì)調(diào)用該 Bean 的 afterPropertiesSet()。在Bean在實(shí)例化的過程中執(zhí)執(zhí)行順序?yàn)椋篊onstructor > @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的監(jiān)聽器,能夠用來(lái)監(jiān)聽事件,典型的觀察者模式。如果容器中有一個(gè)ApplicationListener Bean,每當(dāng)ApplicationContext發(fā)布ApplicationEvent時(shí),ApplicationListener Bean將自動(dòng)被觸發(fā)。這種事件機(jī)制都必須需要程序顯示的觸發(fā)。其中spring有一些內(nèi)置的事件,當(dāng)完成某種操作時(shí)會(huì)發(fā)出某些事件動(dòng)作。比如監(jiān)聽ContextRefreshedEvent事件,當(dāng)所有的bean都初始化完成并被成功裝載后會(huì)觸發(fā)該事件,實(shí)現(xiàn)ApplicationListener接口可以收到監(jiān)聽動(dòng)作,然后可以寫自己的邏輯。同樣事件可以自定義、監(jiān)聽也可以自定義,完全根據(jù)自己的業(yè)務(wù)邏輯來(lái)處理。所以也能做到資源的初始化加載!

@Component
public class DataSourceInitListener implements ApplicationListener<ContextRefreshedEvent> {//ContextRefreshedEvent為啟動(dòng)事件
 
    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) {//判斷是否執(zhí)行過,執(zhí)行過則不再執(zhí)行
            LOGGER.info("初始化systemConfig數(shù)據(jù)");
            systemConfigService.initConfig();
            LOGGER.info("初始化返回消息數(shù)據(jù)");
            systemResultService.initResult();
            LOGGER.info("系統(tǒng)初始化結(jié)束...........");
        }
    }
 
}

全文引用自https://www.cnblogs.com/cnndevelop/p/12064645.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容