springboot?實(shí)現(xiàn)動(dòng)態(tài)刷新配置的詳細(xì)過(guò)程
自定義的配置數(shù)據(jù)源,繼承自Spring框架的 MapPropertySource 類
從一個(gè)名為 my.properties 的文件中讀取配置信息,并在每10秒鐘刷新一次。
這里不加@Component,是因?yàn)椋?br />FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
// 屬性源是按照添加的順序進(jìn)行合并的,后添加的屬性源中的屬性會(huì)覆蓋前面添加的屬性源中的同名屬性。
// 因此,為了確保我們自定義的屬性源中的屬性優(yōu)先級(jí)最高,我們需要將它添加到屬性源列表的最后。這樣就能保證后添加的屬性源中的屬性值會(huì)覆蓋之前的同名屬性。
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 類,從一個(gè)名為 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("開(kāi)始讀取配置文件 {}", 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("忽略配置項(xiàng) {}", line);
continue;
}
String key = pair[0].trim();
String value = pair[1].trim();
logger.debug("讀取配置項(xiàng) {} = {}", 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("讀取配置文件完成,共讀取 {} 個(gè)配置項(xiàng),時(shí)間 {}", newProperties.size(), LocalDateTime.now().format(DATE_TIME_FORMATTER));
}
/**
* 覆蓋 getProperty 方法,實(shí)現(xiàn)實(shí)時(shí)獲取配置
*
* @param key 配置項(xiàng)的 key
* @return 配置項(xiàng)的值
*/
@Override
public Object getProperty(String key) {
return source.get(key);
}
}定義一個(gè)Spring配置類,定義了一個(gè)名為 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;
/**
* 一個(gè)Spring配置類,定義了一個(gè)名為 filePropertiesSource 的Bean,并將其加入到環(huán)境變量中。
*/
@Configuration
public class AutoConfig {
@Bean
public FilePropertiesSource filePropertiesSource(ConfigurableEnvironment environment) {
FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
// 屬性源是按照添加的順序進(jìn)行合并的,后添加的屬性源中的屬性會(huì)覆蓋前面添加的屬性源中的同名屬性。
// 因此,為了確保我們自定義的屬性源中的屬性優(yōu)先級(jí)最高,我們需要將它添加到屬性源列表的最后。這樣就能保證后添加的屬性源中的屬性值會(huì)覆蓋之前的同名屬性。
environment.getPropertySources().addLast(filePropertiesSource);
return filePropertiesSource;
}
}為了方便直接用啟動(dòng)類作為控制層
@DependsOn(“filePropertiesSource”) 依賴于filePropertiesSource,以實(shí)現(xiàn)刷新配置。
@EnableScheduling 實(shí)現(xiàn)定時(shí)刷新
private String userName; 會(huì)被計(jì)算機(jī)名稱覆蓋,計(jì)算機(jī)名稱優(yōu)先級(jí)最高
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);
}
}實(shí)現(xiàn)效果

訪問(wèn):http://localhost:8080/get?key=my-user-id

可見(jiàn)修改user-name無(wú)效,被計(jì)算機(jī)名稱所覆蓋。
這時(shí)候修改my-user-id=

再訪問(wèn):http://localhost:8080/get?key=my-user-id

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

