01.SpringBoot開發雜記-使用工具類,靜態讀取配置檔案中的配置的寫法

长名06發表於2024-09-27

使用工具類,靜態讀取配置檔案中的配置的寫法

@Component
public class ConfigUtils {

    private static ConfigUtils instance;//單例模式持有當前工具類的例項

    private ConfigUtils(){}

    @Value("${system.uploadPath}")
    private String uploadPath;//@Value註解讀取配置,為類物件的屬性
	
  
    @Value("${basicLog}")
    private String basicLog;

    
    @PostConstruct//在建立類物件後,執行一些操作
    public void init(){
        instance = this;//將IOC容器自動建立的工具類的bean例項物件,配置為單例持有的物件
    }

    public static String getUploaderRootPath(){//提供獲取配置的靜態方法
        return instance.uploadPath;
    }
    
    public static String getBasicLog(){
        return instance.basicLog;
    }


}

如果是單體架構的專案,上面的程式碼,已經能夠實現了,無外乎就是多設定幾個屬性,或者屬性很多的話,使用@ConfigurationProperties(prefix = "xxx"),的方式,統一賦值,減少手寫@Value註解。

注意,微服務架構的話,以上寫法,可能會導致一個問題,就是這些配置,可能會存在滯後性。因為上述程式碼,本質是Spring掃描到ConfigUtils類的@Component註解,並生成物件時,@Value註解,從配置檔案中,讀取配置,並設定屬性。在物件建立完畢,依賴注入完畢後,執行到@PostConstruct修飾的init初始化方法時,將IOC容器中的ConfigUtils物件,賦給instance。但是,當在微服務架構中,在配置中心,修改配置檔案,並開啟了動態重新整理功能,雖然動態重新整理,可以重新整理到環境Environment,但是卻無法修改,最初IOC容器中的this物件,這也就導致,看似重新整理了配置中心中的配置,但是使用ConfigUtils.getUploaderRootPath()方法,獲取到的配置,依舊是,應用啟動時,讀取到的舊的配置。

問題是,如何在保證在配置中心的配置檔案修改後,能夠保證使用ConfigUtils獲取到最新的配置呢?

1.要麼就是,每次配置檔案重新整理後,都將配置重新重新整理到配置類的屬性上。

這個很難實現,因為無法控制,什麼時候重新整理,以及重新整理那些類的屬性。也可能是我的技術水平,不高,所以對這一條解決方法,沒有思路。

2.要麼就是,每次獲取屬性時,都獲取最新的(每次獲取配置時,都使用Environment進行獲取)。

public class ConfigUtils {

    private static Environment environment;

    private ConfigUtils(){}

//    private String uploadPath;
//
//    private String basicLog;

    public static void init(Environment env){
        environment = env;
    }

    public static String getUploaderRootPath(){
        return environment.getProperty("upload_path");
    }

    public static String getBasicLog(){
        return environment.getProperty("basicLog");
    }

}

但是上面程式碼,很明顯是錯誤的,因為沒有為environment賦值,什麼時候,賦值呢?當然是配置檔案中的配置都寫入到Environment存放在IOC容器中之後,鑑於配置寫入完成時,沒有一個標誌。可以使用應用啟動完成後,再進行賦值,此時肯定寫入完成了。主啟動類實現CommandLineRunner介面,重寫run(String... args)方法,在其中定義應用啟動完成後,執行後續的一些操作。

@...(註解省略了)
public class XxxApplication implements CommandLineRunner { #org.springframework.boot.CommandLineRunner

    @Resource
    private Environment environment;

    public static void main(String[] args) {
        SpringApplication.run(XxxApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        ConfigUtils.init(environment);
    }

}

這樣,就能保證,動態重新整理後,使用ConfigUtils獲取配置,獲取到最新的。

只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。

相關文章