springboot?實(shí)現(xiàn)動(dòng)態(tài)刷新配置的詳細(xì)過程
自定義的配置數(shù)據(jù)源,繼承自Spring框架的 MapPropertySource 類
從一個(gè)名為 my.properties 的文件中讀取配置信息,并在每10秒鐘刷新一次。
這里不加@Component,是因?yàn)椋?br />FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
// 屬性源是按照添加的順序進(jìn)行合并的,后添加的屬性源中的屬性會覆蓋前面添加的屬性源中的同名屬性。
// 因此,為了確保我們自定義的屬性源中的屬性優(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 類,從一個(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("開始讀取配置文件 {}", 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)行合并的,后添加的屬性源中的屬性會覆蓋前面添加的屬性源中的同名屬性。 // 因此,為了確保我們自定義的屬性源中的屬性優(yōu)先級最高,我們需要將它添加到屬性源列表的最后。這樣就能保證后添加的屬性源中的屬性值會覆蓋之前的同名屬性。 environment.getPropertySources().addLast(filePropertiesSource); return filePropertiesSource; } }
為了方便直接用啟動(dòng)類作為控制層
@DependsOn(“filePropertiesSource”) 依賴于filePropertiesSource,以實(shí)現(xiàn)刷新配置。
@EnableScheduling 實(shí)現(xiàn)定時(shí)刷新
private String userName; 會被計(jì)算機(jī)名稱覆蓋,計(jì)算機(jī)名稱優(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); } }
實(shí)現(xiàn)效果
訪問:http://localhost:8080/get?key=my-user-id
可見修改user-name無效,被計(jì)算機(jī)名稱所覆蓋。
這時(shí)候修改my-user-id=
再訪問:http://localhost:8080/get?key=my-user-id
已實(shí)現(xiàn)刷新:
ext:
@PostConstruct:
用于指定在依賴注入完成后需要執(zhí)行的初始化方法。具體來說,當(dāng)Spring容器完成對一個(gè)bean的依賴注入后,會調(diào)用該bean中使用了@PostConstruct注解的方法。
例如,如果在一個(gè)類中定義了一個(gè)方法,并在該方法上添加了@PostConstruct注解,那么當(dāng)Spring容器初始化該類時(shí),會自動(dòng)調(diào)用該方法,以完成一些必要的初始化操作。
@PostConstruct注解的方法不能帶有任何參數(shù),也不能有返回值,因?yàn)镾pring不會使用這些返回值。如果需要返回一些狀態(tài)信息,可以使用類成員變量來保存這些信息。另外需要注意的是,@PostConstruct注解只能用于非靜態(tài)方法。
@Scheduled(fixedRate = 10_000)
@Scheduled是一個(gè)Spring框架提供的注解,用于實(shí)現(xiàn)基于時(shí)間的任務(wù)調(diào)度。通過在方法上添加@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注解的方法必須是無參方法,且返回類型為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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于controller的異常處理及service層的事務(wù)控制方式
這篇文章主要介紹了關(guān)于controller的異常處理及service層的事務(wù)控制方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02功能強(qiáng)大的TraceId?搭配?ELK使用詳解
這篇文章主要為大家介紹了功能強(qiáng)大的TraceId?搭配?ELK使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09java獲取當(dāng)前時(shí)間并格式化代碼實(shí)例
這篇文章主要介紹了java獲取當(dāng)前時(shí)間并格式化代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08Java類加載異常:java.lang.ClassNotFoundException解決方法
這篇文章主要給大家介紹了關(guān)于Java類加載異常:java.lang.ClassNotFoundException的解決方法,異常是Java編程語言中的一個(gè)標(biāo)準(zhǔn)異常類,它繼承自類,當(dāng)在運(yùn)行時(shí)嘗試加載類時(shí),如果系統(tǒng)找不到指定的類文件就會拋出該異常,需要的朋友可以參考下2023-11-11SpringCloud Feign遠(yuǎn)程調(diào)用實(shí)現(xiàn)詳解
Feign是Netflix公司開發(fā)的一個(gè)聲明式的REST調(diào)用客戶端; Ribbon負(fù)載均衡、 Hystrⅸ服務(wù)熔斷是我們Spring Cloud中進(jìn)行微服務(wù)開發(fā)非?;A(chǔ)的組件,在使用的過程中我們也發(fā)現(xiàn)它們一般都是同時(shí)出現(xiàn)的,而且配置也都非常相似2022-11-11Java中的動(dòng)態(tài)和靜態(tài)編譯實(shí)例詳解
這篇文章主要介紹了Java中的動(dòng)態(tài)和靜態(tài)編譯實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04Netty啟動(dòng)流程服務(wù)端channel初始化源碼分析
這篇文章主要為大家介紹了Netty啟動(dòng)流程服務(wù)端channel初始化源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03