springboot实现动态加载自定义配置 您所在的位置:网站首页 spring自动加载配置文件 springboot实现动态加载自定义配置

springboot实现动态加载自定义配置

2023-07-31 04:03| 来源: 网络整理| 查看: 265

一、背景

在项目开发中,遇到有一个很特殊的需求:有一个系统服务要求必须不依赖Mysql,Redis等中间件来完成可以新增配置信息,删除配置信息,并且要求配置可以被程序感知到,完成不同的逻辑。 后来想了下决定使用定时任务,定时读取配置文件,然后将配置信息定时加载进程序中

二、代码实现 1. pom依赖

其中各个依赖版本跟随项目即可

org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test junit junit test org.projectlombok lombok true com.alibaba fastjson org.apache.commons commons-lang3 2. 新加配置文件 2.1 access-system.properties

自定义配置文件,用于配置允许访问本系统的系统以及系统秘钥,该文件必须放在与jar包平级的config目录下,如需新增配置,将配置按照格式写入,即可自动加载

000001=MDAwMDAxQQ== 000002=MDAwMDAyQg== 000003=MDAwMDAzQw== 2.2 application.properties

springboot项目配置文件

server.port=8082 #设置自动加载配置信息的时间(每分钟执行一次) read.access.system.schedule=0 * * * * ? 2.3 logback.xml

日志配置文件,非核心配置,随意即可

" %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n /app/logs/${APPNAME}/${APPNAME}.log /app/logs/${APPNAME}/${APPNAME}-%d{yyyy-MM-dd}.log 30 %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} [%file:%line] - %msg%n UTF-8 /app/logs/${APPNAME}/${APPNAME}-error.log ERROR ACCEPT DENY /app/logs/${APPNAME}/${APPNAME}-error-%d{yyyy-MM-dd}.log 30 %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} [%file:%line] - %msg%n UTF-8 3. 新建相关实体类 3.1 启动类 package com.task.read; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; /** * 定时读取配置文件加载到程序中 * @EnableScheduling表示对定时任务的支持 * * @author zhang */ @EnableScheduling @SpringBootApplication public class TaskReadConfigApplication { public static void main(String[] args) { SpringApplication.run(TaskReadConfigApplication.class, args); } } 3.1 新建配置文件对应实体类 package com.task.read.entity; import java.io.Serializable; /** * 配置信息的实体类 * * @author zhang * @date 2021-09-03 23:02:43 */ public class AccessSystem implements Serializable { private static final long serialVersionUID = 8333665889439802146L; private String systemId; private String secretKey; public AccessSystem() { } public AccessSystem(String systemId, String secretKey) { this.systemId = systemId; this.secretKey = secretKey; } public String getSystemId() { return systemId; } public void setSystemId(String systemId) { this.systemId = systemId; } public String getSecretKey() { return secretKey; } public void setSecretKey(String secretKey) { this.secretKey = secretKey; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("{") .append("\"systemId\":").append(systemId) .append(", \"secretKey\":").append("******") .append('}'); return sb.toString(); } } 3.2 新建config类用于存储所有配置信息 package com.task.read.config; import com.task.read.entity.AccessSystem; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * 配置了用于存储所有配置信息 * * @author zhang * @date 2021-09-03 23:04:01 */ @Component public class AccessSystemConfig { private List systemList = new ArrayList(); public List getSystemList() { return systemList; } public void setSystemList(List systemList) { this.systemList = systemList; } } 3.3 定时任务类 package com.task.read.schedule; import com.task.read.config.AccessSystemConfig; import com.task.read.entity.AccessSystem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.stream.Collectors; /** * 定时任务,定时读取所有accessSystem配置信息,加载到程序中 * * @author zhang * @date 2021-09-03 23:19:09 */ @Component public class ScheduleTask implements ApplicationRunner { private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleTask.class); private static String configLocation = null; //获取配置文件所在目录 static { //获取当前类所在的目录,即jar包目录 String property = System.getProperty("user.dir"); //获取自定义配置文件的路径 configLocation = property + "/config/access-system.properties"; LOGGER.info("access-system.properties location:[{}]", configLocation); } /** * 项目启动后,会调用该方法 */ @Autowired private AccessSystemConfig accessSystemConfig; @Override public void run(ApplicationArguments args) { LOGGER.info("======================================================================"); LOGGER.info("=== The task for reading the accessSystemConfig has been started ==="); LOGGER.info("======================================================================"); readConfig(); } /** * 定时加载 accessSystem */ @Scheduled(cron = "${read.access.system.schedule}") public void scheduleTask() { readConfig(); } /** * 读取配置,将配置加载到程序中 */ private void readConfig() { LOGGER.info("============= parse accessSystemConfig is start ============="); long startTime = System.currentTimeMillis(); //加载文件 try (FileInputStream inputStream = new FileInputStream(configLocation); Reader reader = new InputStreamReader(inputStream); BufferedReader br = new BufferedReader(reader)) { //存放本次读取出的配置 List newSystemList = new ArrayList(); //将文件映射成properties对象 Properties properties = new Properties(); properties.load(br); //解析properties对象,存入newSystemList中 properties.forEach((k, v) -> { //解析秘钥,并保存 AccessSystem accessSystem = new AccessSystem(k.toString(), v.toString()); newSystemList.add(accessSystem); }); //清空原有数据,并保存新获取到的数据 accessSystemConfig.getSystemList().clear(); accessSystemConfig.setSystemList(newSystemList); } catch (Exception e) { LOGGER.warn("read accessSystemConfig is fail, cause by:", e); } finally { //打印出已加载的系统信息 List systemNoList = accessSystemConfig.getSystemList().stream().map(AccessSystem::getSystemId).collect(Collectors.toList()); LOGGER.info("Loaded systemNoList:{}", systemNoList); LOGGER.info("======= parse accessSystemConfig is complete, cost:{}ms ======", System.currentTimeMillis() - startTime); } } } 3.4 Controller类 package com.task.read.controller; import com.alibaba.fastjson.JSON; import com.task.read.config.AccessSystemConfig; import com.task.read.entity.AccessSystem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 控制器层,简单模拟下 * * @author zhang * @date 2021-09-03 23:13:59 */ @RestController @RequestMapping public class AdminController { private static final Logger LOGGER = LoggerFactory.getLogger(AdminController.class); @Autowired private AccessSystemConfig accessSystemConfig; @GetMapping("/getConfig") public Map getConfig() { Map result = new HashMap(); //这里模拟根据配置 完成不同的逻辑 List systemList = accessSystemConfig.getSystemList(); systemList.forEach(accessSystem -> { result.put(accessSystem.getSystemId(), accessSystem.getSecretKey()); LOGGER.info("accessSystem:{}", JSON.toJSONString(accessSystem)); }); return result; } } 三、 功能测试 1. 系统启动

系统启动后,看下启动日志,如果成功启动,会打印如下信息 在这里插入图片描述

2. postman请求/getConfig接口

请求完成,看具体返回值,是否正常返回 在这里插入图片描述

3. 修改access-system.properties文件

修改配置文件中的内容后,定时任务执行时,就会重新加载配置,这时候再去请求/getConfig接口,应该会随着你的修改而产生变化

四、总结

因为领导催的很急,所以只是做了利用了定时任务来简单的实现,也基本满足了需求,但是如果硬扣的话,这么做是无法做到准实时的,并且肯定还有其他方式来实现,但是我觉得这是比较简单快速的实现了,就这样吧,完事收工



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有