天天看點

SpringBoot進階-SpringBoot中如何配置動态重新整理操作?

作者:架構師面試寶典
SpringBoot進階-SpringBoot中如何配置動态重新整理操作?

在實際工作開發中,我們經常會遇到在項目啟動的時候對應用進行一些初始化的操作,例如對于線程池的初始化、對于證書的初始化等等操作。那麼在面試的時候面試官也會問到在SpringBoot中的動态加載配置相關的内容,那麼下面我們就來看看在Spring Boot中對于配置動态重新整理常用的幾種方式。

第一、通過監聽容器重新整理完擴充點

我們知道在Spring ApplicationContext中提供了基于觀察者模式的事件處理機制,通過ApplicationEvent 和ApplicationListener兩個接口來實作ApplicationContext的事件機制,當然在Spring中也提供了一些内置的事件機制。

ContextRefreshedEvent: ApplicationContext被初始化或者發生重新整理操作的時候,這個事件就會被觸發,當然也可以在ConfigurableApplicationContext接口中使用refresh()方法來觸發。當然這裡需要注意的一點是這裡所指的初始化是當所有的Bean對象都被成功裝載,後處理Bean被檢測并且激活,所有的Singleton Bean都被預執行個體化,這個時候ApplicationContext容器就可以就緒使用了。

ContextStartedEvent:當使用ConfigurationApplicationContext 接口中的start方法啟動ApplicationContext的時候,該事件被觸發。

ContextStoppedEvent:當使用ConfigurationApplicationContext 接口中的stop方法停止ApplicationContext的時候,該事件被觸發。

ContextCloseEvent:當使用ConfigurationApplicationContext 接口的close方法關閉ApplicationContext的時候,該事件被觸發。

RequesthandledEvent:這是一個web-specific事件,用來告知Bean Http請求已經被服務。隻能應用于使用DispatcherServlet的Web應用。在使用Spring 作為前端的MVC控制器的時候,當Spring處理使用者請求結束之後,系統自動觸發該事件。

可以做個簡單的小測試。啟動Spring Boot之後會看到事件内容被列印了。

@Component
public class TestApplicationListener implements 
  ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("觸發了ContextRefreshedEvent事件");
    }
}           

第二、使用Spring Boot的CommandLineRunner接口

在Spring容器被初始化之後會調用CommandLineRunner接口中的run方法,同樣通過這種方式也可以實作動态參數傳遞,而且這種方式要比通過ApplicationListener的方式相對靈活。如下

@Component
public class TestCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println(Arrays.asList(args));
    }
}           

可以在項目啟動的時候通過指令行傳入參數

第三、通過Spring Boot的ApplicationRunner接口

ApplicationRunner和CommandLineRunner都是Spring Boot提供的接口,相對于CommandLineRunner來說對控制台傳入的參數封裝的相對友好一些,可以通過鍵值對的方式來進行參數的傳遞。

@Component
public class TestApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println(args.getOptionNames());
        System.out.println(args.getNonOptionArgs());
        System.out.println(args.getSourceArgs());
    }
}           

可以采用同樣的方式進行參數的傳入測試。

第四、使用@PostConstruct 注解

前面三種方式都是通過容器初始化完成之後做的事情,而@PostConstruct 注解則是針對Bean初始化完成之後來做一些事情,例如對于一些監聽器的注冊、對于一些初始化對象調用。

@PostConstruct 注解一般都是放在Bean的方法上,一旦Bean對象被初始化了,就會調用這個方法對方法中的的内容進行調用。

@Component
public class TestBean {

    @PostConstruct
    public void init(){
        System.out.println("Bean對象被初始化了");
    }
}           

從代碼執行的結果來看,Bean對象初始化的調用要比容器初始化的調用要早,這是由于容器要等待所有的Bean都被加載才能算是初始化完成,這個在前面的内容中我們介紹過。

第五、使用@Bean注解的指定的初始化方法

在使用XML配置檔案的時候我們用到過一個init-method的屬性,這個屬性就是用來指定加載Bean完成之後調用那個方法這裡,我們也是通過注解版的這個屬性來實作這個操作,整個的操作的過程與@PostConstruct注解類似。

首先需要定義一個測試Bean對象

public class TestInitBean {
    public void init(){
        System.out.println("使用Bean注解的InitMethod屬性");
    }
}           

定義配置檔案來注入Bean對象,并且指定初始化方法。

@Configuration
public class TestConfig {

    @Bean(initMethod = "init")
    public TestInitBean testInitBean(){
        return new TestInitBean();
    }

}           

第六、使用InitializingBean接口

InitializingBean的基本用法與@PostConstruct 注解的用法類似,不過就是需要實作afterPropertiesSet()方法,具有一定的代碼侵入性。

@Component
public class InitImplTestBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean初始化完成");
    }
}           

總結

通過上面的幾種方式,我們可以實作動态配置的加載,當然可以實作動态配置加載的方式還有很多不僅局限于這種方式,希望有興趣的讀者多多留意。

繼續閱讀