前言
相信大家在開發(fā)中會有需要外部自定義配置文件塌西,且以外部自定義配置文件中的配置值優(yōu)先筹淫,同時要求對外部自定義配置文件中的配置修改后實時生效的需求饰剥。下面介紹如何實現(xiàn):
引入依賴
項目基于spring boot 2.2.6實現(xiàn)汰蓉,需要spring-cloud-context組件來完成動態(tài)刷新祝钢,具體版本與自己的項目匹配。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
定義外部自定義配置文件路徑常量
package com.harrysharing.demo.constant;
/**
* 系統(tǒng)級常量定義
*
* @author harrysharing
* @date 2020/05/08 10:54:01
* @Copyright: ?2020 harrysharing 版權(quán)所有
*/
public class SystemConstant {
/**
* 自定義配置文件路徑霎冯,分別對應(yīng)生產(chǎn)慷荔、測試监徘、本地
*/
public static final String[] FILE_LIST =
{"/home/demo/myConfig.properties", "/home/demo_test/myConfig.properties", "d:/demo/myConfig.properties"};
}
啟動時加載外部自定義配置文件户敬,且以外部配置優(yōu)先忠怖,同時獲取配置文件最后修改時間
package com.harrysharing.demo.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import com.harrysharing.demo.constant.SystemConstant;
/**
* 加載自定義配置文件
*
* @author harrysharing
* @date 2020/12/15 16:26:09
* @Copyright: ?2020 harrysharing 版權(quán)所有
*/
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
public static long FILE_LAST_MODIFIED = 0L;
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
// if (application.getWebApplicationType().name().equals(WebApplicationType.NONE.name())) {
// return;
// }
for (String conf : SystemConstant.FILE_LIST) {
File f = new File(conf);
if (f.exists()) {
FILE_LAST_MODIFIED = f.lastModified();
Properties p = new Properties();
try {
p.load(new FileInputStream(f));
environment.getPropertySources().addFirst(new PropertiesPropertySource(f.getName(), p));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
@Override
public int getOrder() {
return ConfigFileApplicationListener.DEFAULT_ORDER + 5;
}
}
在src/main/resources目錄下增加META-INF目錄抄瑟,在其下添加spring.factories文件凡泣,指向剛才創(chuàng)建的自定義環(huán)境加載類。內(nèi)容如下:
org.springframework.boot.env.EnvironmentPostProcessor=com.harrysharing.demo.util.CustomEnvironmentPostProcessor
定時檢查配置文件是否修改皮假,若修改則進(jìn)行動態(tài)刷新
package com.harrysharing.demo.job;
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.harrysharing.demo.constant.SystemConstant;
import com.harrysharing.demo.util.CustomEnvironmentPostProcessor;
/**
* 定時檢查配置文件變更及動態(tài)刷新任務(wù)
*
* @author harrysharing
* @date 2020/12/15 16:27:07
* @Copyright: ?2020 harrysharing 版權(quán)所有
*/
@Component
public class ConfigLoadTask {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigLoadTask.class);
@Autowired
private ContextRefresher contextRefresher;
@Scheduled(initialDelay = 1000 * 60, fixedDelay = 1000 * 60)
public void compareAndRefresh() {
for (String conf : SystemConstant.FILE_LIST) {
File f = new File(conf);
if (f.exists()) {
if (CustomEnvironmentPostProcessor.FILE_LAST_MODIFIED == f.lastModified()) {
return;
}
LOGGER.info("發(fā)現(xiàn)配置文件有變更鞋拟,執(zhí)行動態(tài)刷新。conf={}", conf);
contextRefresher.refresh();
break;
}
}
}
}
實際應(yīng)用
在需要動態(tài)刷新配置的類上增加@RefreshScope注解惹资,在需要動態(tài)刷新的配置類變量上增加@Value注解贺纲,同時該類也必須由spring管理。
package com.harrysharing.demo.service;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import com.alibaba.druid.util.StringUtils;
import com.harrysharing.demo.entity.CodeEnum;
import com.harrysharing.demo.exception.BizException;
import com.harrysharing.demo.mapper.UserMasterMapper;
import com.harrysharing.demo.model.UserMaster;
import com.harrysharing.demo.util.Sha256;
import com.harrysharing.framework.db.util.DbUtil;
import com.harrysharing.framework.util.PageInfo;
import com.harrysharing.framework.util.SnowflakeShardingKeyGenerator;
/**
* 用戶管理服務(wù)
*
* @author harrysharing
* @date 2020/08/05 18:29:26
* @Copyright: ?2020 harrysharing 版權(quán)所有
*/
@RefreshScope
@Service
public class UserMasterService {
@Autowired
private UserMasterMapper userMasterMapper;
@Autowired
private SnowflakeShardingKeyGenerator shardingKeyGenerator;
@Value("${maxPageSize}")
private int maxPageSize;
/**
* 根據(jù)條件分頁查詢用戶列表
*
* @param paraMap
* 查詢條件
* @return PageInfo 分頁對象
* @author harrysharing
* @date 2020/08/19 16:33:56
*/
public PageInfo<UserMaster> queryPageList(Map<String, Object> paraMap) {
if (paraMap == null || paraMap.isEmpty()) {
throw new BizException(CodeEnum.INVALID_PARAM);
}
Object paraObj = paraMap.get("page");
if (paraObj == null) {
throw new BizException(CodeEnum.INVALID_PARAM);
}
if (!StringUtils.isNumber(paraObj.toString())) {
throw new BizException(CodeEnum.INVALID_PARAM);
}
int page = Integer.parseInt(paraObj.toString());
int userPageSize = maxPageSize;
paraObj = paraMap.get("pageSize");
if (paraObj != null) {
if (!StringUtils.isNumber(paraObj.toString())) {
throw new BizException(CodeEnum.INVALID_PARAM);
}
userPageSize = Integer.parseInt(paraObj.toString());
}
PageInfo<UserMaster> pi =
DbUtil.queryPageList(userMasterMapper, paraMap, page, userPageSize, "create_time desc", maxPageSize);
if (pi.getSize() == 0) {
throw new BizException(CodeEnum.NO_RESULT);
}
return pi;
}
}