网站建设 金手指排名霸屏,简洁大气网站模板,北京ui设计app制作公司,网站备案容易吗文章目录 一#xff0c;序言二#xff0c;准备工作1. pom.xml引入组件2. 配置文件示例 三#xff0c;自定义配置项动态刷新编码实现1. 定义自定义配置项对象2. 添加注解实现启动时自动注入3. 实现yml文件监听以及文件变化处理 四#xff0c;yaml文件转换为java对象1. 无法使… 文章目录 一序言二准备工作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 只需引入前者。
dependencygroupIdcom.fasterxml.jackson.dataformat/groupIdartifactIdjackson-dataformat-yaml/artifactId
/dependency2. 配置文件示例
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;Data
public class Person
{private String name;private Integer age;private Boolean happy;private Date birth;private MapString, Object maps;private ListObject lists;private Dog dog;
}import lombok.Data;Data
public 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 MapString, Object maps;private ListObject lists;private Dog dog;
}3. 实现yml文件监听以及文件变化处理 /*** 监听文件变化推荐*/
Slf4j
Component
public 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的数据为了避免报错同时定义了MapString, Object spring 来保存spring节点数据。
import lombok.Data;/*** 定义Result实体绑定Personbr* 与下面的Spring配置等价br* Componentbr* ConfigurationProperties(prefix person)br* public class Person { ... }*/
Data
public class Result
{private Person person;private MapString, 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;Slf4j
public 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.yml
version: 3
services:hello:image: registry.cn-shanghai.aliyuncs.com/00fly/spring-config-refresh:1.0.0container_name: config-refreshdeploy:resources:limits:cpus: 1memory: 300Mreservations:cpus: 0.05memory: 200Mports:- 8080:8080environment:JAVA_OPTS: -server -Xms200m -Xmx200m -Djava.security.egdfile:/dev/./urandomrestart: on-failurelogging:driver: json-fileoptions:max-size: 5mmax-file: 1//goto docker\restart.sh
#!/bin/bash
docker-compose down docker system prune -f docker-compose up -d docker stats
//goto docker\stop.sh
#!/bin/bash
docker-compose down
//goto Dockerfile
FROM openjdk:8-jre-alpineRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo Asia/Shanghai /etc/timezoneCOPY target/*.jar /app.jarEXPOSE 8080CMD [--server.port8080]ENTRYPOINT [java,-jar,/app.jar]
//goto pom.xml
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.fly/groupIdartifactIdspring-config-refresh/artifactIdversion1.0.0/versionpackagingjar/packagingpropertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingmaven.build.timestamp.formatyyyyMMdd-HH/maven.build.timestamp.formatdocker.hubregistry.cn-shanghai.aliyuncs.com/docker.hubjava.version1.8/java.versionskipTeststrue/skipTests/propertiesparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.2.4.RELEASE/version/parentdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdexclusionsexclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-logging/artifactId/exclusion/exclusions/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-log4j2/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactIdexclusionsexclusiongroupIdorg.apache.tomcat/groupIdartifactIdtomcat-jdbc/artifactId/exclusion/exclusions/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion1.2.16/version/dependencydependencygroupIdcom.github.xiaoymin/groupIdartifactIdknife4j-spring-boot-starter/artifactIdversion2.0.5/version/dependencydependencygroupIdcom.h2database/groupIdartifactIdh2/artifactIdscoperuntime/scope/dependencydependencygroupIdcommons-configuration/groupIdartifactIdcommons-configuration/artifactIdversion1.10/version/dependencydependencygroupIdcom.fasterxml.jackson.dataformat/groupIdartifactIdjackson-dataformat-yaml/artifactId/dependencydependencygroupIdcom.fasterxml.jackson.dataformat/groupIdartifactIdjackson-dataformat-properties/artifactId/dependencydependencygroupIdcommons-io/groupIdartifactIdcommons-io/artifactIdversion2.6/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdscopeprovided/scope/dependency!-- Test --dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-configuration2/artifactIdversion2.8.0/versionscopetest/scope/dependencydependencygroupIdcommons-beanutils/groupIdartifactIdcommons-beanutils/artifactIdversion1.9.4/versionscopetest/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildfinalName${project.artifactId}-${project.version}/finalNamepluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin!-- 添加docker-maven插件 --plugingroupIdio.fabric8/groupIdartifactIddocker-maven-plugin/artifactIdversion0.41.0/versionexecutionsexecutionphasepackage/phasegoalsgoalbuild/goalgoalpush/goalgoalremove/goal/goals/execution/executionsconfiguration!-- 连接到带docker环境的linux服务器编译image --!--dockerHosthttp://192.168.182.10:2375/dockerHost--!-- Docker 推送镜像仓库地址 --pushRegistry${docker.hub}/pushRegistryimagesimage!--推送到私有镜像仓库镜像名需要添加仓库地址 --name${docker.hub}/00fly/${project.artifactId}:${project.version}-UTC-${maven.build.timestamp}/name!--定义镜像构建行为 --builddockerFileDir${project.basedir}/dockerFileDir/build/imageimagename${docker.hub}/00fly/${project.artifactId}:${project.version}/namebuilddockerFileDir${project.basedir}/dockerFileDir/build/image/images/configuration/plugin/pluginsresourcesresourcedirectorysrc/main/java/directoryexcludesexclude**/*.java/exclude/excludes/resourceresourcedirectorysrc/main/resources/directoryincludesinclude**/**/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);}BeanConditionalOnWebApplicationCommandLineRunner 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.java
package 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
EnableSwagger2
public 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.java
package 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 [产品/模块版本]*/
Configuration
public 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.java
package 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
Configuration
public class SysDataBaseConfig
{AutowiredJdbcTemplate jdbcTemplate;AutowiredConfigurableEnvironment environment;PostConstructpublic void initDatabasePropertySource(){// 取配置信息列表并过滤空值ListSysConfig data jdbcTemplate.query(SELECT key, value FROM sys_config WHERE status 1, new BeanPropertyRowMapper(SysConfig.class));MapString, 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 [产品/模块版本]*/
Data
class SysConfig
{private String key;private String value;
}
//goto src\main\java\com\fly\core\JsonResult.java
package com.fly.core;import lombok.Data;/*** * 结果对象* * author 00fly* version [版本号, 2021年5月2日]* see [相关类/方法]* since [产品/模块版本]*/
Data
public class JsonResultT
{private T data;private boolean success;private String errorCode;private String message;public JsonResult(){super();}public static T JsonResultT success(T data){JsonResultT r new JsonResult();r.setData(data);r.setSuccess(true);return r;}public static JsonResult? success(){JsonResultObject r new JsonResult();r.setSuccess(true);return r;}public static JsonResultObject error(String code, String msg){JsonResultObject r new JsonResult();r.setSuccess(false);r.setErrorCode(code);r.setMessage(msg);return r;}public static JsonResultObject error(String msg){return error(500, msg);}
}
//goto src\main\java\com\fly\core\utils\SpringContextUtils.java
package 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
Component
public 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(ClassT 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 egserver.port* return* see [类、类#方法、类#成员]*/public static String getProperty(String key){return applicationContext.getEnvironment().getProperty(key, );}
}
//goto src\main\java\com\fly\core\utils\YamlUtils.java
package 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转MapString, String* * param yamlContent* return* throws IOException*/public static MapString, 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.java
package 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
Service
public 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.java
package 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
Component
public 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.java
package 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
Component
public 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.java
package com.fly.refresh.entity;import lombok.Data;Data
public class Dog
{private String name;private Integer age;
}
//goto src\main\java\com\fly\refresh\entity\Person.java
package 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 MapString, Object maps;private ListObject lists;private Dog dog;
}
//goto src\main\java\com\fly\refresh\entity\Result.java
package com.fly.refresh.entity;import java.util.Map;import lombok.Data;/*** 定义Result实体绑定Person、Welcomebr* 与下面的Spring配置等价br* br* Componentbr* ConfigurationProperties(prefix person)br* public class Person { ... }br* br* Componentbr* ConfigurationProperties(prefix welcome)br* public class Welcome { ... }*/
Data
public class Result
{private Person person;private Welcome welcome;private MapString, Object spring;
}
//goto src\main\java\com\fly\refresh\entity\Welcome.java
package 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注解在SysDataBaseConfigbr* 2. spring.profiles.active指定dev即application-dev.ymlbr* 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.java
package 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
Component
public 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.java
package 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
ConditionalOnNotWebApplication
public 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.java
package 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.yml
person: 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.yml
server:port: 8080servlet:context-path: /session:timeout: 1800
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.propertiesh2:console:enabled: truepath: /h2-consolesettings:web-allow-others: trueprofiles:active:- dev
//goto src\main\resources\jdbc-h2.properties
druid.usernamesa
druid.password
druid.urljdbc:h2:mem:reload;database_to_upperfalse
druid.driverClassNameorg.h2.Driver
//goto src\main\resources\sql\schema.sql
CREATE 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.properties
schedule.myjob.cron */5 * * * * ?
//goto src\main\resources\welcome.properties
welcome.message Hello 00fly in welcome.properties
//goto src\test\java\com\fly\refresh\config2\ResourceReloadConfigTest.java
package 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 [产品/模块版本]*/
Slf4j
public class ResourceReloadConfigTest
{ReloadingFileBasedConfigurationBuilderPropertiesConfiguration 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 ReloadingFileBasedConfigurationBuilderPropertiesConfiguration(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.java
package 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;Slf4j
public 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.java
package 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;Slf4j
public 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.java
package 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;Slf4j
public 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{messageHello 00fly in test2.yml}} {welcome.messageHello 00fly in test2.yml}}
}
//goto src\test\java\com\fly\refresh\yaml\YAMLMapperTest.java
package 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;Slf4j
public 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.properties
schedule.myjob.cron */5 * * * * ?
//goto src\test\resources\log4j2.xml
?xml version1.0 encodingUTF-8?
configuration statusoff monitorInterval0appendersconsole nameConsole targetsystem_outpatternLayout pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %c - %msg%n //console/appendersloggersroot levelINFOappender-ref refConsole //root/loggers
/configuration
//goto src\test\resources\prop\complex.properties
welcome.messageHello 00fly in complex
//goto src\test\resources\yaml\complex.yml
welcome:message: Hello 00fly in test2.yml
//goto src\test\resources\yaml\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: 13. 运行说明
系统启动后从内存数据库h2表sys_config加载配置从application-dev.yml加载配置修改application-dev.yml、welcome.properties可以看到配置被动态刷新/show/refresh 接口调用刷新配置如需要测试数据库配置请在application.yml设置spring.profiles.active为test或者prod 有任何问题和建议都可以向我提问讨论,大家一起进步谢谢!
-over-