springboot?實現(xiàn)動態(tài)刷新配置的詳細過程
自定義的配置數(shù)據(jù)源,繼承自Spring框架的 MapPropertySource 類
從一個名為 my.properties 的文件中讀取配置信息,并在每10秒鐘刷新一次。
這里不加@Component,是因為:
FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
// 屬性源是按照添加的順序進行合并的,后添加的屬性源中的屬性會覆蓋前面添加的屬性源中的同名屬性。
// 因此,為了確保我們自定義的屬性源中的屬性優(yōu)先級最高,我們需要將它添加到屬性源列表的最后。這樣就能保證后添加的屬性源中的屬性值會覆蓋之前的同名屬性。
environment.getPropertySources().addLast(filePropertiesSource);
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.MapPropertySource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
/**
*
* 自定義的配置數(shù)據(jù)源,繼承自Spring框架的 MapPropertySource 類,從一個名為 my.properties 的文件中讀取配置信息,并在每10秒鐘刷新一次。
* @author Administrator
*/
@Slf4j
//@Component
public class FilePropertiesSource extends MapPropertySource {
private static final Logger logger = LoggerFactory.getLogger(FilePropertiesSource.class);
private static final String CONFIG_FILE_NAME = "my.properties";
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public FilePropertiesSource() {
super("filePropertiesSource", new HashMap<>());
}
/**
* 從配置文件中讀取配置,10s 更新一次
*/
@PostConstruct
@Scheduled(fixedRate = 10_000)
public void refreshSource() throws IOException {
logger.info("開始讀取配置文件 {}", CONFIG_FILE_NAME);
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE_NAME);
if (inputStream == null) {
throw new FileNotFoundException("配置文件 " + CONFIG_FILE_NAME + " 不存在");
}
Map<String, String> newProperties = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (StringUtils.isEmpty(line) || line.startsWith("#")) {
continue;
}
String[] pair = StringUtils.split(line, "=");
if (pair == null || pair.length != 2) {
logger.warn("忽略配置項 {}", line);
continue;
}
String key = pair[0].trim();
String value = pair[1].trim();
logger.debug("讀取配置項 {} = {}", key, value);
newProperties.put(key, value);
}
} catch (IOException e) {
logger.error("讀取配置文件 {} 出現(xiàn)異常:{}", CONFIG_FILE_NAME, e.getMessage(), e);
throw e;
}
synchronized (this) {
source.clear();
source.putAll(newProperties);
}
logger.info("讀取配置文件完成,共讀取 {} 個配置項,時間 {}", newProperties.size(), LocalDateTime.now().format(DATE_TIME_FORMATTER));
}
/**
* 覆蓋 getProperty 方法,實現(xiàn)實時獲取配置
*
* @param key 配置項的 key
* @return 配置項的值
*/
@Override
public Object getProperty(String key) {
return source.get(key);
}
}定義一個Spring配置類,定義了一個名為 filePropertiesSource 的Bean,并將其加入到環(huán)境變量中。
import com.lfsun.bootdynamicenv.config.FilePropertiesSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* 一個Spring配置類,定義了一個名為 filePropertiesSource 的Bean,并將其加入到環(huán)境變量中。
*/
@Configuration
public class AutoConfig {
@Bean
public FilePropertiesSource filePropertiesSource(ConfigurableEnvironment environment) {
FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
// 屬性源是按照添加的順序進行合并的,后添加的屬性源中的屬性會覆蓋前面添加的屬性源中的同名屬性。
// 因此,為了確保我們自定義的屬性源中的屬性優(yōu)先級最高,我們需要將它添加到屬性源列表的最后。這樣就能保證后添加的屬性源中的屬性值會覆蓋之前的同名屬性。
environment.getPropertySources().addLast(filePropertiesSource);
return filePropertiesSource;
}
}為了方便直接用啟動類作為控制層
@DependsOn(“filePropertiesSource”) 依賴于filePropertiesSource,以實現(xiàn)刷新配置。
@EnableScheduling 實現(xiàn)定時刷新
private String userName; 會被計算機名稱覆蓋,計算機名稱優(yōu)先級最高
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@DependsOn("filePropertiesSource")
@EnableScheduling
@RestController
@SpringBootApplication
public class Application {
@Autowired
private Environment environment;
@Value("${user-name}")
private String userName;
@GetMapping(path = "get")
public String getProperty(String key) {
return userName + " | " + environment.getProperty(key);
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}實現(xiàn)效果

訪問:http://localhost:8080/get?key=my-user-id

可見修改user-name無效,被計算機名稱所覆蓋。
這時候修改my-user-id=

再訪問:http://localhost:8080/get?key=my-user-id

已實現(xiàn)刷新:
ext:
@PostConstruct:
用于指定在依賴注入完成后需要執(zhí)行的初始化方法。具體來說,當Spring容器完成對一個bean的依賴注入后,會調(diào)用該bean中使用了@PostConstruct注解的方法。
例如,如果在一個類中定義了一個方法,并在該方法上添加了@PostConstruct注解,那么當Spring容器初始化該類時,會自動調(diào)用該方法,以完成一些必要的初始化操作。
@PostConstruct注解的方法不能帶有任何參數(shù),也不能有返回值,因為Spring不會使用這些返回值。如果需要返回一些狀態(tài)信息,可以使用類成員變量來保存這些信息。另外需要注意的是,@PostConstruct注解只能用于非靜態(tài)方法。
@Scheduled(fixedRate = 10_000)
@Scheduled是一個Spring框架提供的注解,用于實現(xiàn)基于時間的任務調(diào)度。通過在方法上添加@Scheduled注解,并指定相應的屬性,可以使得該方法在指定的時間間隔內(nèi)自動執(zhí)行。
例如,@Scheduled(fixedRate = 10_000)表示每隔10秒執(zhí)行一次該方法。fixedRate屬性指定了執(zhí)行方法的時間間隔,單位為毫秒。除此之外,還可以使用cron表達式指定執(zhí)行時間,如@Scheduled(cron = “0 0 12 * * ?”)表示每天中午12點執(zhí)行一次該方法。
需要注意的是,使用@Scheduled注解的方法必須是無參方法,且返回類型為void或Future。如果需要傳遞參數(shù)或返回結(jié)果,可以使用實例變量或方法返回值進行傳遞。同時,為了使得@Scheduled注解生效,需要在啟動類上面@EnableScheduling
到此這篇關于springboot 實現(xiàn)動態(tài)刷新配置的文章就介紹到這了,更多相關springboot動態(tài)刷新配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
關于controller的異常處理及service層的事務控制方式
這篇文章主要介紹了關于controller的異常處理及service層的事務控制方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
Java類加載異常:java.lang.ClassNotFoundException解決方法
這篇文章主要給大家介紹了關于Java類加載異常:java.lang.ClassNotFoundException的解決方法,異常是Java編程語言中的一個標準異常類,它繼承自類,當在運行時嘗試加載類時,如果系統(tǒng)找不到指定的類文件就會拋出該異常,需要的朋友可以參考下2023-11-11
SpringCloud Feign遠程調(diào)用實現(xiàn)詳解
Feign是Netflix公司開發(fā)的一個聲明式的REST調(diào)用客戶端; Ribbon負載均衡、 Hystrⅸ服務熔斷是我們Spring Cloud中進行微服務開發(fā)非常基礎的組件,在使用的過程中我們也發(fā)現(xiàn)它們一般都是同時出現(xiàn)的,而且配置也都非常相似2022-11-11

