前言
相信大家在开发中会有需要外部自定义配置文件,且以外部自定义配置文件中的配置值优先,同时要求对外部自定义配置文件中的配置修改后实时生效的需求。下面介绍如何实现:
引入依赖
项目基于spring boot 2.2.6实现,需要spring-cloud-context组件来完成动态刷新,具体版本与自己的项目匹配。
<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;
/**
* 系统级常量定义
*
* @author harrysharing
* @date 2020/05/08 10:54:01
* @Copyright: ©2020 harrysharing 版权所有
*/
public class SystemConstant {
/**
* 自定义配置文件路径,分别对应生产、测试、本地
*/
public static final String[] FILE_LIST =
{"/home/demo/myConfig.properties", "/home/demo_test/myConfig.properties", "d:/demo/myConfig.properties"};
}
启动时加载外部自定义配置文件,且以外部配置优先,同时获取配置文件最后修改时间
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 版权所有
*/
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文件,指向刚才创建的自定义环境加载类。内容如下:
org.springframework.boot.env.EnvironmentPostProcessor=com.harrysharing.demo.util.CustomEnvironmentPostProcessor
定时检查配置文件是否修改,若修改则进行动态刷新
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;
/**
* 定时检查配置文件变更及动态刷新任务
*
* @author harrysharing
* @date 2020/12/15 16:27:07
* @Copyright: ©2020 harrysharing 版权所有
*/
@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("发现配置文件有变更,执行动态刷新。conf={}", conf);
contextRefresher.refresh();
break;
}
}
}
}
实际应用
在需要动态刷新配置的类上增加@RefreshScope注解,在需要动态刷新的配置类变量上增加@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;
/**
* 用户管理服务
*
* @author harrysharing
* @date 2020/08/05 18:29:26
* @Copyright: ©2020 harrysharing 版权所有
*/
@RefreshScope
@Service
public class UserMasterService {
@Autowired
private UserMasterMapper userMasterMapper;
@Autowired
private SnowflakeShardingKeyGenerator shardingKeyGenerator;
@Value("${maxPageSize}")
private int maxPageSize;
/**
* 根据条件分页查询用户列表
*
* @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;
}
}
网友评论