当前位置:首页 >> 智能终端演进 >> 【springboot配置项动态刷新】与【yaml文件转换为java对象】,奥林巴斯数码相机怎么样

【springboot配置项动态刷新】与【yaml文件转换为java对象】,奥林巴斯数码相机怎么样

cpugpu芯片开发光刻机 智能终端演进 1
文件名:【springboot配置项动态刷新】与【yaml文件转换为java对象】,奥林巴斯数码相机怎么样 【springboot配置项动态刷新】与【yaml文件转换为java对象】

文章目录 一,序言二,准备工作1. pom.xml引入组件2. 配置文件示例 三,自定义配置项动态刷新编码实现1. 定义自定义配置项对象2. 添加注解实现启动时自动注入3. 实现yml文件监听以及文件变化处理 四,yaml文件转换为java对象1. 无法使用前缀绑定的处理2. 实现yaml文件转换java对象 五、完整代码1. 代码结构2. 完整代码备份3. 运行说明

一,序言

springboot 配置文件一般以yaml方式保存,除了系统配置项如spring、server等外,还有我们自定义的配置项,方便系统启动时自动注入。

自定义的配置项一般是动态配置项,在系统运行过程中,可能需要在线修改,来实现自定义的配置项不停服更新,也就是类似于spring-cloud-starter-config的动态刷新。

由于系统不重启,无法通过自动注入的方式自动更新自定义配置, 这儿便需要我们手动加载yaml文件,转换为java对象,将变化赋值到spring管理的对象中

二,准备工作

采用最常见的snakeyaml、YAMLMapper来实现yaml文件处理。

1. pom.xml引入组件

因 jackson-dataformat-yaml 已经包含snakeyaml ,只需引入前者。

<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-yaml</artifactId></dependency> 2. 配置文件示例

sample.yml

spring:datasource:url: ${druid.url}username: ${druid.username}password: ${druid.password}driverClassName: ${druid.driverClassName}type: com.alibaba.druid.pool.DruidDataSourcesqlScriptEncoding: utf-8schema: classpath:sql/schema.sqlcontinue-on-error: truedruid:initial-size: 5 # 初始化大小min-idle: 10 # 最小连接数max-active: 20 # 最大连接数max-wait: 60000 # 获取连接时的最大等待时间min-evictable-idle-time-millis: 300000 # 一个连接在池中最小生存的时间,单位是毫秒time-between-eviction-runs-millis: 60000 # 多久才进行一次检测需要关闭的空闲连接,单位是毫秒validation-query: SELECT 1 # 检测连接是否有效的 SQL语句,为空时以下三个配置均无效test-on-borrow: true # 申请连接时执行validationQuery检测连接是否有效,默认true,开启后会降低性能test-on-return: true # 归还连接时执行validationQuery检测连接是否有效,默认false,开启后会降低性能test-while-idle: true # 申请连接时如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效,默认false,建议开启,不影响性能devtools:restart:exclude: application-dev.yml,welcome.propertiesperson: name: qinjiangage: 18happy: falsebirth: 2000-01-01maps: {k1: v1,k2: v2}lists:- code- girl- musicdog:name: 旺财age: 1 三,自定义配置项动态刷新编码实现 1. 定义自定义配置项对象 import java.util.Date;import java.util.List;import java.util.Map;import lombok.Data;@Datapublic class Person{private String name;private Integer age;private Boolean happy;private Date birth;private Map<String, Object> maps;private List<Object> lists;private Dog dog;} import lombok.Data;@Datapublic class Dog{private String name;private Integer age;} 2. 添加注解实现启动时自动注入

在Person类添加 @Component、@ConfigurationProperties(prefix = “person”) 实现自动注入,spring管理

@Data@Component@ConfigurationProperties(prefix = "person")public class Person{private String name;private Integer age;private Boolean happy;private Date birth;private Map<String, Object> maps;private List<Object> lists;private Dog dog;} 3. 实现yml文件监听以及文件变化处理 /*** 监听文件变化(推荐)*/@Slf4j@Componentpublic class ReloadByFileAlterationMonitor{@Autowiredprivate Welcome welcome;/*** thread-safe*/YAMLMapper yamlMapper = new YAMLMapper();/*** 初始化yml文件监听器*/@PostConstructpublic void initYamlMonitor(){try{URL url = ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX);if (ResourceUtils.isFileURL(url)){FileAlterationObserver observer = new FileAlterationObserver(url.getPath(), FileFilterUtils.suffixFileFilter(".yml"));observer.addListener(new FileAlterationListenerAdaptor(){@Overridepublic void onFileChange(File file){log.info("★★★★★★★★ {} changed.", file.getName());if (StringUtils.equals("application-dev.yml", file.getName())){try{// yaml to JavaBeanString text = FileUtils.readFileToString(file, StandardCharsets.UTF_8);JavaBean javaBean = yamlMapper.readValue(text, JavaBean.class);if (javaBean != null && javaBean.getWelcome() != null){String value = javaBean.getWelcome().getMessage();log.info("#### autoRefresh to: {}", value);welcome.setMessage(value);}}catch (IOException e){log.error(e.getMessage(), e.getCause());}}}});long interval = TimeUnit.SECONDS.toMillis(10);FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);monitor.start();}}catch (Exception e){log.error(e.getMessage(), e.getCause());}}} 四,yaml文件转换为java对象 1. 无法使用前缀绑定的处理

定义Result 使用Person person绑定yaml中前缀为person的数据,为了避免报错,同时定义了Map<String, Object> spring 来保存spring节点数据。

import lombok.Data;/*** 定义Result实体绑定Person<br>* 与下面的Spring配置等价<br>* @Component<br>* @ConfigurationProperties(prefix = "person")<br>* public class Person { ... }*/@Datapublic class Result{private Person person;private Map<String, Object> spring;} 2. 实现yaml文件转换java对象

注意: org.yaml.snakeyaml.Yaml 非线程安全,建议使用 YAMLMapper

import java.io.IOException;import java.nio.charset.StandardCharsets;import org.apache.commons.io.IOUtils;import org.junit.BeforeClass;import org.junit.Test;import org.springframework.core.io.ClassPathResource;import org.yaml.snakeyaml.Yaml;import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;import com.fly.refresh.entity.Result;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class SampleTest{static String yamlText;YAMLMapper yamlMapper = new YAMLMapper();@BeforeClasspublic static void init(){try{yamlText = IOUtils.toString(new ClassPathResource("yaml/sample.yml").getURL(), StandardCharsets.UTF_8);log.info("yamlText => {}", yamlText);}catch (IOException e){log.error(e.getMessage(), e.getCause());}}/*** 解析带prefix的yaml*/@Testpublic void test()throws IOException{Result result = new Yaml().loadAs(yamlText, Result.class);log.info("snakeyaml toJavaBean: {}", result);result = yamlMapper.readValue(yamlText, Result.class);log.info("yamlMapper toJavaBean: {}", result);} } 五、完整代码 1. 代码结构

2. 完整代码备份

如何使用下面的备份文件恢复成原始的项目代码,请移步查阅:神奇代码恢复工具

//goto docker\docker-compose.ymlversion: '3'services:hello:image: registry.cn-shanghai.aliyuncs.com/00fly/spring-config-refresh:1.0.0container_name: config-refreshdeploy:resources:limits:cpus: '1'memory: 300Mreservations:cpus: '0.05'memory: 200Mports:- 8080:8080environment:JAVA_OPTS: -server -Xms200m -Xmx200m -Djava.security.egd=file:/dev/./urandomrestart: on-failurelogging:driver: json-fileoptions:max-size: 5mmax-file: '1'//goto docker\restart.sh#!/bin/bashdocker-compose down && docker system prune -f && docker-compose up -d && docker stats//goto docker\stop.sh#!/bin/bashdocker-compose down//goto DockerfileFROM openjdk:8-jre-alpineRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezoneCOPY target/*.jar /app.jarEXPOSE 8080CMD ["--server.port=8080"]ENTRYPOINT ["java","-jar","/app.jar"]//goto pom.xml<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.fly</groupId><artifactId>spring-config-refresh</artifactId><version>1.0.0</version><packaging>jar</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.build.timestamp.format>yyyyMMdd-HH</maven.build.timestamp.format><docker.hub>registry.cn-shanghai.aliyuncs.com</docker.hub><java.version>1.8</java.version><skipTests>true</skipTests></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.4.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><exclusions><exclusion><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.16</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>2.0.5</version></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency><dependency><groupId>commons-configuration</groupId><artifactId>commons-configuration</artifactId><version>1.10</version></dependency><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-yaml</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-properties</artifactId></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><!-- Test --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-configuration2</artifactId><version>2.8.0</version><scope>test</scope></dependency><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.4</version><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><finalName>${project.artifactId}-${project.version}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!-- 添加docker-maven插件 --><plugin><groupId>io.fabric8</groupId><artifactId>docker-maven-plugin</artifactId><version>0.41.0</version><executions><execution><phase>package</phase><goals><goal>build</goal><goal>push</goal><goal>remove</goal></goals></execution></executions><configuration><!-- 连接到带docker环境的linux服务器编译image --><!--<dockerHost>http://192.168.182.10:2375</dockerHost>--><!-- Docker 推送镜像仓库地址 --><pushRegistry>${docker.hub}</pushRegistry><images><image><!--推送到私有镜像仓库,镜像名需要添加仓库地址 --><name>${docker.hub}/00fly/${project.artifactId}:${project.version}-UTC-${maven.build.timestamp}</name><!--定义镜像构建行为 --><build><dockerFileDir>${project.basedir}</dockerFileDir></build></image><image><name>${docker.hub}/00fly/${project.artifactId}:${project.version}</name><build><dockerFileDir>${project.basedir}</dockerFileDir></build></image></images></configuration></plugin></plugins><resources><resource><directory>src/main/java</directory><excludes><exclude>**/*.java</exclude></excludes></resource><resource><directory>src/main/resources</directory><includes><include>**/**</include></includes></resource></resources></build></project>//goto src\main\java\com\fly\BootApplication.javapackage com.fly;import org.apache.commons.lang3.ArrayUtils;import org.apache.commons.lang3.SystemUtils;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.WebApplicationType;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.PropertySource;import org.springframework.scheduling.annotation.EnableScheduling;import com.fly.core.utils.SpringContextUtils;import lombok.extern.slf4j.Slf4j;/*** * SpringBoot 启动入口* * @author 00fly* @version [版本号, 2018年7月20日]* @see [相关类/方法]* @since [产品/模块版本]*/@Slf4j@EnableScheduling@SpringBootApplication@PropertySource("classpath:jdbc-h2.properties")public class BootApplication{public static void main(String[] args){// args = new String[] {"--noweb"};boolean web = !ArrayUtils.contains(args, "--noweb");log.info("############### with Web Configuration: {} #############", web);new SpringApplicationBuilder(BootApplication.class).web(web ? WebApplicationType.SERVLET : WebApplicationType.NONE).run(args);}@Bean@ConditionalOnWebApplicationCommandLineRunner init(){return args -> {if (SystemUtils.IS_OS_WINDOWS){log.info("★★★★★★★★ now open Browser ★★★★★★★★ ");String url = SpringContextUtils.getServerBaseURL();Runtime.getRuntime().exec("cmd /c start /min " + url + "/doc.html");Runtime.getRuntime().exec("cmd /c start /min " + url + "/h2-console");}};}}//goto src\main\java\com\fly\core\config\Knife4jConfig.javapackage com.fly.core.config;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import io.swagger.annotations.ApiOperation;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;/*** knife4j** @author jack*/@Configuration@EnableSwagger2public class Knife4jConfig{@Value("${knife4j.enable: true}")private boolean enable;@BeanDocket api(){return new Docket(DocumentationType.SWAGGER_2).enable(enable).apiInfo(apiInfo()).groupName("Rest API").select().apis(RequestHandlerSelectors.basePackage("com.fly.refresh.web")).apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build();}private ApiInfo apiInfo(){return new ApiInfoBuilder().title("接口API").description("接口文档").termsOfServiceUrl("http://00fly.online/").version("1.0.0").build();}}//goto src\main\java\com\fly\core\config\ScheduleThreadPoolConfig.javapackage com.fly.core.config;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledThreadPoolExecutor;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.concurrent.CustomizableThreadFactory;import org.springframework.scheduling.config.ScheduledTaskRegistrar;/*** * Schedule线程池配置* * @author 00fly* @version [版本号, 2023年10月22日]* @see [相关类/方法]* @since [产品/模块版本]*/@Configurationpublic class ScheduleThreadPoolConfig implements SchedulingConfigurer{@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar){ScheduledExecutorService service = new ScheduledThreadPoolExecutor(8, new CustomizableThreadFactory("schedule-pool-"));taskRegistrar.setScheduler(service);}}//goto src\main\java\com\fly\core\config\SysDataBaseConfig.javapackage com.fly.core.config;import java.util.List;import java.util.Map;import java.util.stream.Collectors;import javax.annotation.PostConstruct;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.MapPropertySource;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import lombok.Data;import lombok.extern.slf4j.Slf4j;/*** * 数据库配置信息加载类* * @author 00fly* @version [版本号, 2021年10月24日]* @see [相关类/方法]* @since [产品/模块版本]*/@Slf4j@Configurationpublic class SysDataBaseConfig{@AutowiredJdbcTemplate jdbcTemplate;@AutowiredConfigurableEnvironment environment;@PostConstructpublic void initDatabasePropertySource(){// 取配置信息列表并过滤空值List<SysConfig> data = jdbcTemplate.query("SELECT `key`, `value` FROM sys_config WHERE `status` = '1'", new BeanPropertyRowMapper<>(SysConfig.class));Map<String, Object> collect = data.stream().filter(p -> StringUtils.isNoneEmpty(p.getKey(), p.getValue())).collect(Collectors.toMap(SysConfig::getKey, SysConfig::getValue));log.info("====== init from database ===== {}", collect);// 追加配置到系统变量中,name取值随意environment.getPropertySources().addLast(new MapPropertySource("sys_config", collect));}}/*** * 配置信息实体对象* * @author 00fly* @version [版本号, 2021年10月24日]* @see [相关类/方法]* @since [产品/模块版本]*/@Dataclass SysConfig{private String key;private String value;}//goto src\main\java\com\fly\core\JsonResult.javapackage com.fly.core;import lombok.Data;/*** * 结果对象* * @author 00fly* @version [版本号, 2021年5月2日]* @see [相关类/方法]* @since [产品/模块版本]*/@Datapublic class JsonResult<T>{private T data;private boolean success;private String errorCode;private String message;public JsonResult(){super();}public static <T> JsonResult<T> success(T data){JsonResult<T> r = new JsonResult<>();r.setData(data);r.setSuccess(true);return r;}public static JsonResult<?> success(){JsonResult<Object> r = new JsonResult<>();r.setSuccess(true);return r;}public static JsonResult<Object> error(String code, String msg){JsonResult<Object> r = new JsonResult<>();r.setSuccess(false);r.setErrorCode(code);r.setMessage(msg);return r;}public static JsonResult<Object> error(String msg){return error("500", msg);}}//goto src\main\java\com\fly\core\utils\SpringContextUtils.javapackage com.fly.core.utils;import java.net.InetAddress;import java.net.UnknownHostException;import javax.servlet.ServletContext;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;import org.springframework.util.Assert;import lombok.extern.slf4j.Slf4j;/*** Spring Context 工具类* * @author 00fly**/@Slf4j@Componentpublic class SpringContextUtils implements ApplicationContextAware{private static ApplicationContext applicationContext;/*** web服务器基准URL*/private static String SERVER_BASE_URL = null;@Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException{log.info("###### execute setApplicationContext ######");SpringContextUtils.applicationContext = applicationContext;}public static ApplicationContext getApplicationContext(){return applicationContext;}public static <T> T getBean(Class<T> clazz){Assert.notNull(applicationContext, "applicationContext is null");return applicationContext.getBean(clazz);}/*** execute @PostConstruct May be SpringContextUtils not inited, throw NullPointerException* * @return*/public static String getActiveProfile(){Assert.notNull(applicationContext, "applicationContext is null");String[] profiles = applicationContext.getEnvironment().getActiveProfiles();return StringUtils.join(profiles, ",");}/*** can use in @PostConstruct* * @param context* @return*/public static String getActiveProfile(ApplicationContext context){Assert.notNull(context, "context is null");String[] profiles = context.getEnvironment().getActiveProfiles();return StringUtils.join(profiles, ",");}/*** get web服务基准地址,一般为 http://${ip}:${port}/${contentPath}* * @return* @throws UnknownHostException* @see [类、类#方法、类#成员]*/public static String getServerBaseURL()throws UnknownHostException{if (SERVER_BASE_URL == null){ServletContext servletContext = getBean(ServletContext.class);Assert.notNull(servletContext, "servletContext is null");String ip = InetAddress.getLocalHost().getHostAddress();SERVER_BASE_URL = "http://" + ip + ":" + getProperty("server.port") + servletContext.getContextPath();}return SERVER_BASE_URL;}/*** getProperty* * @param key eg:server.port* @return* @see [类、类#方法、类#成员]*/public static String getProperty(String key){return applicationContext.getEnvironment().getProperty(key, "");}}//goto src\main\java\com\fly\core\utils\YamlUtils.javapackage com.fly.core.utils;import java.io.IOException;import java.util.Map;import java.util.Properties;import com.fasterxml.jackson.databind.JsonNode;import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;/*** * yaml转换工具* * @author 00fly* @version [版本号, 2023年4月25日]* @see [相关类/方法]* @since [产品/模块版本]*/public final class YamlUtils{private static YAMLMapper yamlMapper = new YAMLMapper();private static JavaPropsMapper javaPropsMapper = new JavaPropsMapper();/*** yaml转Json字符串* * @param yamlContent* @return* @throws IOException*/public static String yamlToJson(String yamlContent)throws IOException{JsonNode jsonNode = yamlMapper.readTree(yamlContent);return jsonNode.toPrettyString();}/*** yaml转Map<String, String>* * @param yamlContent* @return* @throws IOException*/public static Map<String, String> yamlToMap(String yamlContent)throws IOException{JsonNode jsonNode = yamlMapper.readTree(yamlContent);return javaPropsMapper.writeValueAsMap(jsonNode);}/*** yaml转properties* * @param yamlContent* @return* @throws IOException*/public static Properties yamlToProperties(String yamlContent)throws IOException{JsonNode jsonNode = yamlMapper.readTree(yamlContent);return javaPropsMapper.writeValueAsProperties(jsonNode);}/*** yaml转properties字符串* * @param yamlContent* @return* @throws IOException*/public static String yamlToPropText(String yamlContent)throws IOException{JsonNode jsonNode = yamlMapper.readTree(yamlContent);return javaPropsMapper.writeValueAsString(jsonNode);}private YamlUtils(){super();}}//goto src\main\java\com\fly\refresh\back\ReloadByDataBase.javapackage com.fly.refresh.back;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import com.fly.refresh.entity.Welcome;import lombok.extern.slf4j.Slf4j;/*** 数据库配置表手动刷新*/@Slf4j@Servicepublic class ReloadByDataBase{@AutowiredWelcome welcome;@AutowiredJdbcTemplate jdbcTemplate;/*** 更新到数据库* * @param message* @return*/public int update(String message){int count = jdbcTemplate.update("UPDATE sys_config SET `value`=? WHERE `key` = 'welcome.message'", message);if (count > 0){log.info("#### autoRefresh to: {}", message);welcome.setMessage(message);}return count;}}//goto src\main\java\com\fly\refresh\back\ReloadByFileAlterationMonitor.javapackage com.fly.refresh.back;import java.io.File;import java.io.IOException;import java.net.URL;import java.nio.charset.StandardCharsets;import java.util.Properties;import java.util.concurrent.TimeUnit;import javax.annotation.PostConstruct;import org.apache.commons.io.FileUtils;import org.apache.commons.io.filefilter.FileFilterUtils;import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;import org.apache.commons.io.monitor.FileAlterationMonitor;import org.apache.commons.io.monitor.FileAlterationObserver;import org.apache.commons.lang.StringUtils;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.support.PropertiesLoaderUtils;import org.springframework.stereotype.Component;import org.springframework.util.ResourceUtils;import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;import com.fly.refresh.entity.Person;import com.fly.refresh.entity.Result;import com.fly.refresh.entity.Welcome;import lombok.extern.slf4j.Slf4j;/*** 监听文件变化(推荐)*/@Slf4j@Componentpublic class ReloadByFileAlterationMonitor{@Autowiredprivate Person person;@Autowiredprivate Welcome welcome;/*** thread-safe*/YAMLMapper yamlMapper = new YAMLMapper();/*** thread-safe*/JavaPropsMapper javaPropsMapper = new JavaPropsMapper();/*** 初始化yml文件监听器*/@PostConstructpublic void initYamlMonitor(){try{URL url = ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX);if (ResourceUtils.isFileURL(url)){FileAlterationObserver observer = new FileAlterationObserver(url.getPath(), FileFilterUtils.suffixFileFilter(".yml"));observer.addListener(new FileAlterationListenerAdaptor(){@Overridepublic void onFileChange(File file){log.info("★★★★★★★★ {} changed.", file.getName());if (StringUtils.equals("application-dev.yml", file.getName())){try{// yaml to JavaBeanString text = FileUtils.readFileToString(file, StandardCharsets.UTF_8);Result javaBean = yamlMapper.readValue(text, Result.class);// Welcome属性拷贝if (javaBean != null && javaBean.getWelcome() != null){Welcome from = javaBean.getWelcome();BeanUtils.copyProperties(from, welcome);log.info("#### autoRefresh to: {}", welcome);}// Person属性拷贝if (javaBean != null && javaBean.getPerson() != null){Person from = javaBean.getPerson();BeanUtils.copyProperties(from, person);log.info("#### autoRefresh to: {}", person);}}catch (IOException e){log.error(e.getMessage(), e.getCause());}}}});long interval = TimeUnit.SECONDS.toMillis(10);FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);monitor.start();}}catch (Exception e){log.error(e.getMessage(), e.getCause());}}/*** 初始化Properties文件监听器*/@PostConstructpublic void initPropsMonitor(){try{URL url = ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX);if (ResourceUtils.isFileURL(url)){FileAlterationObserver observer = new FileAlterationObserver(url.getPath(), FileFilterUtils.suffixFileFilter(".properties"));observer.addListener(new FileAlterationListenerAdaptor(){@Overridepublic void onFileChange(File file){log.info("★★★★★★★★ {} changed.", file.getName());if (StringUtils.equals("welcome.properties", file.getName())){try{// Properties to JavaBeanProperties prop = PropertiesLoaderUtils.loadProperties(new ClassPathResource(file.getName()));Result javaBean = javaPropsMapper.readPropertiesAs(prop, Result.class);if (javaBean != null && javaBean.getWelcome() != null){String value = javaBean.getWelcome().getMessage();log.info("#### autoRefresh to: {}", value);welcome.setMessage(value);}}catch (IOException e){log.error(e.getMessage(), e.getCause());}}}});long interval = TimeUnit.SECONDS.toMillis(10);FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);monitor.start();}}catch (Exception e){log.error(e.getMessage(), e.getCause());}}}//goto src\main\java\com\fly\refresh\back\ReloadByReloadingStrategy.javapackage com.fly.refresh.back;import javax.annotation.PostConstruct;import org.apache.commons.configuration.ConfigurationException;import org.apache.commons.configuration.FileConfiguration;import org.apache.commons.configuration.PropertiesConfiguration;import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import com.fly.refresh.entity.Welcome;import lombok.extern.slf4j.Slf4j;/*** 文件重加载策略(不推荐)*/@Slf4j@Componentpublic class ReloadByReloadingStrategy{String lastMsg;@AutowiredWelcome welcome;FileConfiguration propConfig;/*** 初始化properties文件重加载策略*/@PostConstructpublic void initReloadingStrategy(){try{// 只支持propertiespropConfig = new PropertiesConfiguration("welcome.properties");FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();strategy.setRefreshDelay(10000L);propConfig.setReloadingStrategy(strategy);lastMsg = propConfig.getString("welcome.message");}catch (ConfigurationException e){log.error(e.getMessage(), e.getCause());}}/*** 配置变更时刷新*/@Scheduled(initialDelay = 30000L, fixedRate = 10000L)public void autoRefresh(){// 是否变更,何时刷新逻辑实现String message = propConfig.getString("welcome.message");if (!StringUtils.equals(message, lastMsg)){log.info("#### autoRefresh to: {}, after properties Changed", message);welcome.setMessage(message);lastMsg = message;}}}//goto src\main\java\com\fly\refresh\entity\Dog.javapackage com.fly.refresh.entity;import lombok.Data;@Datapublic class Dog{private String name;private Integer age;}//goto src\main\java\com\fly\refresh\entity\Person.javapackage com.fly.refresh.entity;import java.util.Date;import java.util.List;import java.util.Map;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.format.annotation.DateTimeFormat;import org.springframework.stereotype.Component;import lombok.Data;@Data@Component@ConfigurationProperties(prefix = "person")public class Person{private String name;private Integer age;private Boolean happy;@DateTimeFormat(pattern = "yyyy-MM-dd")private Date birth;private Map<String, Object> maps;private List<Object> lists;private Dog dog;}//goto src\main\java\com\fly\refresh\entity\Result.javapackage com.fly.refresh.entity;import java.util.Map;import lombok.Data;/*** 定义Result实体绑定Person、Welcome<br>* 与下面的Spring配置等价<br>* <br>* @Component<br>* @ConfigurationProperties(prefix = "person")<br>* public class Person { ... }<br>* <br>* @Component<br>* @ConfigurationProperties(prefix = "welcome")<br>* public class Welcome { ... }*/@Datapublic class Result{private Person person;private Welcome welcome;private Map<String, Object> spring;}//goto src\main\java\com\fly\refresh\entity\Welcome.javapackage com.fly.refresh.entity;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Lazy;import org.springframework.stereotype.Component;import lombok.Data;/*** * Welcome配置文件实体<br>* 使用@Lazy待SysDataBaseConfig方法initDatabasePropertySource执行完再注入<br>* 否则仅使用数据库初始化时开发环境和Jar运行message值不一致* * @author 00fly* @version [版本号, 2023年11月3日]* @see [相关类/方法]* @since [产品/模块版本]*/@Data@Lazy@Component@ConfigurationProperties(prefix = "welcome")public class Welcome{/*** message赋值方式:<br>* 1. Configuration注解在SysDataBaseConfig<br>* 2. spring.profiles.active指定dev即application-dev.yml<br>* 3. welcome.properties内容变更时触发<br>* 4. /show/refresh接口被调用时触发<br>* 方式1、2有竞争,不能严格区分先后*/private String message = "hello, 00fly in java!";}//goto src\main\java\com\fly\refresh\job\SimpleJob.javapackage com.fly.refresh.job;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import com.fly.refresh.entity.Person;import com.fly.refresh.entity.Welcome;import lombok.extern.slf4j.Slf4j;/*** * SimpleJob* * @author 00fly* @version [版本号, 2022年11月30日]* @see [相关类/方法]* @since [产品/模块版本]*/@Slf4j@Componentpublic class SimpleJob{@Autowiredprivate Person person;@Autowiredprivate Welcome welcome;/*** 不能实时刷新*/@Value("#{welcome.message}")private String message;@Scheduled(cron = "*/10 * * * * ?")public void run(){log.info("---- autoRefresh: {} | fixed: {}", welcome.getMessage(), message);log.info("**** {}, {}", welcome, person);}}//goto src\main\java\com\fly\refresh\ResourceReloadConfig.javapackage com.fly.refresh;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Date;import java.util.ResourceBundle;import java.util.concurrent.ScheduledThreadPoolExecutor;import javax.annotation.PostConstruct;import org.apache.commons.configuration.ConfigurationException;import org.apache.commons.configuration.PropertiesConfiguration;import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;import org.apache.commons.io.IOUtils;import org.apache.commons.lang.math.RandomUtils;import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.scheduling.Trigger;import org.springframework.scheduling.TriggerContext;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.concurrent.CustomizableThreadFactory;import org.springframework.scheduling.config.ScheduledTaskRegistrar;import org.springframework.scheduling.support.CronTrigger;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;/*** 配置文件实时刷新* * @author 00fly* @version [版本号, 2017年4月25日]* @see [相关类/方法]* @since [产品/模块版本]*/@Slf4j@Component@ConditionalOnNotWebApplicationpublic class ResourceReloadConfig implements SchedulingConfigurer{PropertiesConfiguration jobConfig;Resource cron = new ClassPathResource("test/cron.properties");ResourceBundle job = ResourceBundle.getBundle("test/job");@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar){// 配置公共Schedule线程池taskRegistrar.setScheduler(new ScheduledThreadPoolExecutor(8, new CustomizableThreadFactory("schedule-pool-")));// 配置TriggerTasktaskRegistrar.addTriggerTask(new Runnable(){@Overridepublic void run(){// 任务逻辑log.info("★★★★★★★ {} run ★★★★★★★", getClass().getName());}}, new Trigger(){@Overridepublic Date nextExecutionTime(TriggerContext triggerContext){String cron = readCronText();return new CronTrigger(cron).nextExecutionTime(triggerContext);}});}/*** 初始化*/@PostConstructpublic void init(){try{jobConfig = new PropertiesConfiguration("test/job.properties");FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();strategy.setRefreshDelay(60000L);// 刷新周期1分钟jobConfig.setReloadingStrategy(strategy);}catch (ConfigurationException e){log.error(e.getMessage(), e.getCause());}}/*** 3种方式读取CronText* * @return*/private String readCronText(){String cronText = "*/10 * * * * ?";Integer key = RandomUtils.nextInt(3);switch (key){case 0:cronText = jobConfig.getString("schedule.myjob.cron");break;case 1:try{cronText = IOUtils.toString(cron.getURL(), StandardCharsets.UTF_8);}catch (IOException e){log.error(e.getMessage(), e.getCause());}break;case 2:ResourceBundle.clearCache();cronText = job.getString("schedule.myjob.cron");break;default:break;}log.info("**** key: {} ==> {}", key, cronText);return cronText;}}//goto src\main\java\com\fly\refresh\web\ShowController.javapackage com.fly.refresh.web;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.fly.core.JsonResult;import com.fly.refresh.back.ReloadByDataBase;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiOperation;@RestController@Api(tags = "演示接口")@RequestMapping("/show")public class ShowController{@AutowiredReloadByDataBase reloadByDataBase;@ApiOperation("刷新欢迎语")@PostMapping("/refresh")@ApiImplicitParam(name = "message", value = "欢迎语", example = "热烈欢迎活捉洪真英,生擒李知恩! ", required = true)public JsonResult<?> refresh(String message){if (StringUtils.isBlank(message)){return JsonResult.error("message不能为空");}boolean success = reloadByDataBase.update(message) > 0;return success ? JsonResult.success(message) : JsonResult.error("刷新欢迎语失败");}}//goto src\main\resources\application-dev.ymlperson: name: qinjiangage: 18happy: falsebirth: 2000-01-01maps: {k1: v1,k2: v2}lists:- code- girl- musicdog:name: 旺财age: 1welcome:message: Hello 00fly in application-dev.yml//goto src\main\resources\application-prod.yml//goto src\main\resources\application-test.yml//goto src\main\resources\application.ymlserver:port: 8080servlet:context-path: /session:timeout: 1800spring:datasource:url: ${druid.url}username: ${druid.username}password: ${druid.password}driverClassName: ${druid.driverClassName}type: com.alibaba.druid.pool.DruidDataSourcesqlScriptEncoding: utf-8schema: classpath:sql/schema.sqlcontinue-on-error: truedruid:initial-size: 5 # 初始化大小min-idle: 10 # 最小连接数max-active: 20 # 最大连接数max-wait: 60000 # 获取连接时的最大等待时间min-evictable-idle-time-millis: 300000 # 一个连接在池中最小生存的时间,单位是毫秒time-between-eviction-runs-millis: 60000 # 多久才进行一次检测需要关闭的空闲连接,单位是毫秒validation-query: SELECT 1 # 检测连接是否有效的 SQL语句,为空时以下三个配置均无效test-on-borrow: true # 申请连接时执行validationQuery检测连接是否有效,默认true,开启后会降低性能test-on-return: true # 归还连接时执行validationQuery检测连接是否有效,默认false,开启后会降低性能test-while-idle: true # 申请连接时如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效,默认false,建议开启,不影响性能devtools:restart:exclude: application-dev.yml,welcome.propertiesh2:console:enabled: truepath: /h2-consolesettings:web-allow-others: trueprofiles:active:- dev//goto src\main\resources\jdbc-h2.propertiesdruid.username=sadruid.password=druid.url=jdbc:h2:mem:reload;database_to_upper=falsedruid.driverClassName=org.h2.Driver//goto src\main\resources\sql\schema.sqlCREATE TABLE IF NOT EXISTS `sys_config` (`id` bigint NOT NULL AUTO_INCREMENT,`key` varchar(100),`value` varchar(200),`description` varchar(200),`status` varchar(20),`version` bigint,`creater` varchar(50),`create_time` datetime,`modifier` varchar(50),`modify_time` datetime,PRIMARY KEY (`id`));INSERT INTO `sys_config` VALUES ('1', 'welcome.message', CONCAT('hello from db, rand ' ,CAST(RAND()*65536 AS INT)), '系统提示语', '1', '0', 'admin', now(), 'admin', now());//goto src\main\resources\test\cron.properties*/5 * * * * ?//goto src\main\resources\test\job.propertiesschedule.myjob.cron = */5 * * * * ?//goto src\main\resources\welcome.propertieswelcome.message = Hello 00fly in welcome.properties//goto src\test\java\com\fly\refresh\config2\ResourceReloadConfigTest.javapackage com.fly.refresh.config2;import java.nio.charset.StandardCharsets;import java.util.concurrent.TimeUnit;import org.apache.commons.configuration2.PropertiesConfiguration;import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;import org.apache.commons.configuration2.builder.fluent.Configurations;import org.apache.commons.configuration2.builder.fluent.Parameters;import org.apache.commons.configuration2.builder.fluent.PropertiesBuilderParameters;import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;import org.apache.commons.configuration2.ex.ConfigurationException;import org.apache.commons.configuration2.io.ClasspathLocationStrategy;import org.apache.commons.configuration2.io.FileLocationStrategy;import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;import org.junit.Before;import org.junit.Test;import org.springframework.core.io.ClassPathResource;import lombok.extern.slf4j.Slf4j;/*** Configuration2配置文件实时刷新 https://www.geek-share.com/detail/2727072209.html* * @author 00fly* @version [版本号, 2017年4月25日]* @see [相关类/方法]* @since [产品/模块版本]*/@Slf4jpublic class ResourceReloadConfigTest{ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder;/*** 初始化*/@Beforepublic void init(){// 文件扫描策略// FileLocationStrategy strategy = new CombinedLocationStrategy(Arrays.asList(new ClasspathLocationStrategy(), new FileSystemLocationStrategy()));FileLocationStrategy strategy = new ClasspathLocationStrategy();PropertiesBuilderParameters propertiesBuilderParameters = new Parameters().properties().setEncoding(StandardCharsets.UTF_8.name()).setPath(new ClassPathResource("job.properties").getPath()).setLocationStrategy(strategy).setListDelimiterHandler(new DefaultListDelimiterHandler(',')).setReloadingRefreshDelay(2000L).setThrowExceptionOnMissing(true);builder = new ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class).configure(propertiesBuilderParameters);PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(), null, 60, TimeUnit.SECONDS);trigger.start();}@Testpublic void read()throws ConfigurationException{// 直接读取Configurations configs = new Configurations();FileBasedConfigurationBuilder.setDefaultEncoding(PropertiesConfiguration.class, StandardCharsets.UTF_8.name());PropertiesConfiguration propConfig = configs.properties(new ClassPathResource("job.properties").getPath());log.info("propConfig:{}", propConfig.getString("schedule.myjob.cron"));}/*** https://cloud.tencent.com/developer/article/1600688* * @throws ConfigurationException*/@Testpublic void test()throws ConfigurationException{PropertiesConfiguration configuration = builder.getConfiguration();log.info("{}", configuration.getString("schedule.myjob.cron"));}}//goto src\test\java\com\fly\refresh\prop\JavaPropsMapperTest.javapackage com.fly.refresh.prop;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Map;import java.util.Properties;import org.apache.commons.io.IOUtils;import org.junit.Test;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.support.PropertiesLoaderUtils;import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;import com.fly.core.utils.YamlUtils;import com.fly.refresh.entity.Result;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class JavaPropsMapperTest{/*** thread-safe*/JavaPropsMapper javaPropsMapper = new JavaPropsMapper();/*** Properties to Bean* * @throws IOException*/@Testpublic void testPropToBean()throws IOException{Properties complex = PropertiesLoaderUtils.loadProperties(new ClassPathResource("prop/complex.properties"));// 多层结构转换成了嵌套MapMap<?, ?> map = javaPropsMapper.readPropertiesAs(complex, Map.class);log.info("***** PropToBean:{} => {}", complex, map);Result javaBean = javaPropsMapper.readPropertiesAs(complex, Result.class);log.info("***** PropToBean:{} => {}", complex, javaBean);}/*** Properties to Bean* * @throws IOException*/@Testpublic void testPropToBean2()throws IOException{String text = IOUtils.toString(new ClassPathResource("yaml/sample.yml").getURL(), StandardCharsets.UTF_8);Properties props = YamlUtils.yamlToProperties(text);props.keySet().forEach(key -> {log.info("{} => {}", key, props.get(key));});Result result = javaPropsMapper.readPropertiesAs(props, Result.class);log.info("***** PropToBean:{}", result);}}//goto src\test\java\com\fly\refresh\yaml\SampleTest.javapackage com.fly.refresh.yaml;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Properties;import org.apache.commons.io.IOUtils;import org.junit.BeforeClass;import org.junit.Test;import org.springframework.core.io.ClassPathResource;import org.yaml.snakeyaml.Yaml;import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;import com.fly.core.utils.YamlUtils;import com.fly.refresh.entity.Result;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class SampleTest{static String yamlText;/*** thread-safe*/YAMLMapper yamlMapper = new YAMLMapper();@BeforeClasspublic static void init(){try{yamlText = IOUtils.toString(new ClassPathResource("yaml/sample.yml").getURL(), StandardCharsets.UTF_8);log.info("yamlText => {}", yamlText);}catch (IOException e){log.error(e.getMessage(), e.getCause());}}/*** 解析带prefix的yaml*/@Testpublic void test()throws IOException{Result result = new Yaml().loadAs(yamlText, Result.class);log.info("snakeyaml toJavaBean: {}", result);result = yamlMapper.readValue(yamlText, Result.class);log.info("yamlMapper toJavaBean: {}", result);}@Testpublic void test2()throws IOException{// TODO: yamlText截取person内容转换为Person对象Properties props = YamlUtils.yamlToProperties(yamlText);log.info("Properties: {}", props);Result result = new JavaPropsMapper().readPropertiesAs(props, Result.class);log.info("***** PropToBean:{}", result);}}//goto src\test\java\com\fly\refresh\yaml\SnakeYamlTest.javapackage com.fly.refresh.yaml;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Properties;import org.apache.commons.io.IOUtils;import org.junit.BeforeClass;import org.junit.Test;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.yaml.snakeyaml.Yaml;import com.fly.core.utils.YamlUtils;import com.fly.refresh.entity.Result;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class SnakeYamlTest{private static String text;@BeforeClasspublic static void init(){try{Resource resource = new ClassPathResource("yaml/complex.yml");text = IOUtils.toString(resource.getURL(), StandardCharsets.UTF_8);log.info("yamlText => {}", text);}catch (IOException e){log.error(e.getMessage(), e.getCause());}}@Testpublic void test(){Yaml yaml = new Yaml();Result javaBean = yaml.loadAs(text, Result.class);log.info("***** toJavaBean => {}", javaBean);}/*** 注意区别*/@Testpublic void testPk()throws IOException{Yaml yaml = new Yaml();Properties prop1 = yaml.loadAs(text, Properties.class);Properties prop2 = YamlUtils.yamlToProperties(text);log.info("** PK ** {} <=> {}", prop1, prop2);// {welcome={message=Hello 00fly in test2.yml}} <=> {welcome.message=Hello 00fly in test2.yml}}}//goto src\test\java\com\fly\refresh\yaml\YAMLMapperTest.javapackage com.fly.refresh.yaml;import java.io.IOException;import java.nio.charset.StandardCharsets;import org.apache.commons.io.IOUtils;import org.junit.Test;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;import com.fly.refresh.entity.Result;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class YAMLMapperTest{/*** thread-safe*/YAMLMapper yamlMapper = new YAMLMapper();@Testpublic void test()throws IOException{Resource resource = new ClassPathResource("yaml/complex.yml");String text = IOUtils.toString(resource.getURL(), StandardCharsets.UTF_8);log.info("***** complex.yml yamlText => {}", text);Result javaBean = yamlMapper.readValue(text, Result.class);log.info("***** toJavaBean => {}", javaBean);// 报错com.fasterxml.jackson.databind.exc.MismatchedInputException// Properties prop = yamlMapper.readValue(text, Properties.class);// log.info("***** toJavaBean => {}", prop);}}//goto src\test\resources\job.propertiesschedule.myjob.cron = */5 * * * * ?//goto src\test\resources\log4j2.xml<?xml version="1.0" encoding="UTF-8"?><configuration status="off" monitorInterval="0"><appenders><console name="Console" target="system_out"><patternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %c - %msg%n" /></console></appenders><loggers><root level="INFO"><appender-ref ref="Console" /></root></loggers></configuration>//goto src\test\resources\prop\complex.propertieswelcome.message=Hello 00fly in complex//goto src\test\resources\yaml\complex.ymlwelcome:message: Hello 00fly in test2.yml//goto src\test\resources\yaml\sample.ymlspring:datasource:url: ${druid.url}username: ${druid.username}password: ${druid.password}driverClassName: ${druid.driverClassName}type: com.alibaba.druid.pool.DruidDataSourcesqlScriptEncoding: utf-8schema: classpath:sql/schema.sqlcontinue-on-error: truedruid:initial-size: 5 # 初始化大小min-idle: 10 # 最小连接数max-active: 20 # 最大连接数max-wait: 60000 # 获取连接时的最大等待时间min-evictable-idle-time-millis: 300000 # 一个连接在池中最小生存的时间,单位是毫秒time-between-eviction-runs-millis: 60000 # 多久才进行一次检测需要关闭的空闲连接,单位是毫秒validation-query: SELECT 1 # 检测连接是否有效的 SQL语句,为空时以下三个配置均无效test-on-borrow: true # 申请连接时执行validationQuery检测连接是否有效,默认true,开启后会降低性能test-on-return: true # 归还连接时执行validationQuery检测连接是否有效,默认false,开启后会降低性能test-while-idle: true # 申请连接时如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效,默认false,建议开启,不影响性能devtools:restart:exclude: application-dev.yml,welcome.propertiesperson: name: qinjiangage: 18happy: falsebirth: 2000-01-01maps: {k1: v1,k2: v2}lists:- code- girl- musicdog:name: 旺财age: 1 3. 运行说明 系统启动后从内存数据库h2表sys_config加载配置,从application-dev.yml加载配置修改application-dev.yml、welcome.properties可以看到配置被动态刷新/show/refresh 接口调用刷新配置如需要测试数据库配置,请在application.yml设置spring.profiles.active为test或者prod

有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!

-over-

协助本站SEO优化一下,谢谢!
关键词不能为空
同类推荐
«    2025年12月    »
1234567
891011121314
15161718192021
22232425262728
293031
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
搜索
最新留言
文章归档
网站收藏
友情链接