@RefreshScope 刷新配置使用

RefeshScope 简易剥析

@RefreshScope详解

Springboot 使用@RefreshScope 注解,实现配置文件的动态加载

简易应用:

1、添加@RefreshScope注解

如果是使用@Value("${test.message}"),在引用类上添加注解

@Slf4j
@RefreshScope
@RestController
@RequestMapping("/test")
public class TestController {

    @Value("${test.message}") //引入配置
    private String message;


    @GetMapping("/testMethod")
    public Response<List<Map<String, String>>> testMethod() {
        log.info("message:" + message);
        return Response.success(message);
    }
}

如果是使用自定义注解配置类@ConfigurationProperties(prefix = "test"),在配置类添加注解,使用类直接引入

@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "test")
public class ErrorMsgConfigProperties {

    /**
     * 转化异常列表
     */
    private List<Map<String, String>> errorMsgList;

}
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private ErrorMsgConfigProperties errorMsgConfigProperties;

    @GetMapping("/testMethod")
    public Response<List<Map<String, String>>> testMethod() {
        List<Map<String, String>> errorMsgList = errorMsgConfigProperties.getErrorMsgList();
        return Response.success(errorMsgList);
    }
}

2、引入必要依赖和配置


        <!-- 使用@RefreshScope注解 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <version>2.6.0</version>
        </dependency>
        <!-- 使用actuator实现手动刷新 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
            <version>3.0.4</version>
        </dependency>

application.yml添加配置项


#注意2.0.3版本后暴露/refresh接入点的方式与旧版本不同,需要手动设置暴露点。
management:
  endpoints:
    web:
      exposure:
        include: "*" #默认值暴露 /actuator/info和/actuator/health,没有暴露/actuator/bus-refresh,这里把所有endpoints都暴露
#  server:
#    port: 1234 #actuator的端口可以单独定义,如果不定义的话,默认为{server.port}

3、运行项目,检验结果

推荐使用外部依赖jar启动(将application.yml文件置于启动jar的同等级目录),查看直观且方便修改,随后启动: jar -jar xxxx.jar

初步运行 localhost:9232/api/v1/test/testMethod,结果为:

{
    "code": "0",
    "message": "success",
    "requestId": null,
    "data": [
        {
            "code": "default",
            "message": "服务异常,请稍后重试!"
        }
    ]
}

接着修改配置文件内容(注,该配置文件为编译后文件,使用编译器的话,在target下;使用命令打包后启动的话,在classes下),直接打开外部依赖文件,修改内容后,

运行刷新链接:localhost:9232/api/v1/actuator/refresh  

因为配置了项目链接前缀,没配置的 请求: localhost:9232/actuator/refresh

[
    "test.info[0].message"
]

刷新结果会展示出你修改的参数,把涉及修改后差异的参数名返回,流程可参看顶部的“@RefreshScope详解”

现在再运行请求 localhost:9232/api/v1/test/testMethod,结果为:

{
    "code": "0",
    "message": "success",
    "requestId": null,
    "data": [
        {
            "code": "default",
            "message": "服务异常,请稍后重试!123123"
        }
    ]
}

刷新结果实现!

4、扩展实践

通过接口修改配置文件内容并使其生效,demo如下:


@Slf4j
@RefreshScope
@RestController
@RequestMapping(value = "test")
public class TestController {

    @Autowired
    private ObjectButton objectButton;


    @GetMapping(value = "/getButtonValue")
    public String getButtonValue() {
        return "此时的buttonStr:" + objectButton.getButtonStr();
    }

    @GetMapping(value = "/updateButtonValue")
    public String updateButtonValue(String value) {

        System.out.println("修改前:" + objectButton.getButtonStr());
        String fileName = "application.properties";

        Map<String, String> keyValueMap = new HashMap<>();
        keyValueMap.put("open.buttonStr", value);
        updateProperties(fileName, keyValueMap);

        return "此时的buttonStr:" + objectButton.getButtonStr();
    }

    /**
     * 传递键值对的Map,更新properties文件
     *
     * @param fileName    文件名(放在resource源包目录下),需要后缀
     * @param keyValueMap 键值对Map
     */
    public void updateProperties(String fileName, Map<String, String> keyValueMap) {

        Map<String, String> newkeyValueMap = new HashMap<>();
        //getResource方法使用了utf-8对路径信息进行了编码,当路径中存在中文和空格时,他会对这些字符进行转换,这样,
        //得到的往往不是我们想要的真实路径,在此,调用了URLDecoder的decode方法进行解码,以便得到原始的中文及空格路径。
        String filePath = PropertiesUtil.class.getClassLoader().getResource(fileName).getFile();
        Properties props = null;
        BufferedWriter bw = null;

        try {
            filePath = URLDecoder.decode(filePath, "utf-8");
            log.debug("updateProperties propertiesPath:" + filePath);
            props = PropertiesLoaderUtils.loadProperties(new ClassPathResource(fileName));
            for(Object key:props.keySet()){
                newkeyValueMap.put(key.toString() , props.get(key).toString());
            }
            log.debug("updateProperties old:" + props);

            // 写入属性文件
            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath)));

            props.clear();// 清空旧的文件
            //将新值覆盖掉原有的
            for (String key : keyValueMap.keySet()) {
                newkeyValueMap.put(key, keyValueMap.get(key));
            }

            //将所有新值写入配置文件
            for (String key : newkeyValueMap.keySet()) {
                System.out.println(key + ":" +  newkeyValueMap.get(key));
                props.setProperty(key, newkeyValueMap.get(key));
            }

            log.debug("updateProperties new:" + props);
            props.store(bw, "");
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

//   直接内部请求刷新配置,虽然会生效,不过会报timeout
//        String url = "http://localhost:9232/api/v1/actuator/refresh" ;
//        try {
//            String result = HttpUtil.doPost(url, "{}");
//            log.info("result : " + result);
//            return;
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
    }
}

配置文件读取和修改参考:java 4种方式读取配置文件 + 修改配置文件

调用修改接口后,访问 localhost:9232/api/v1/actuator/refresh,实现动态刷新。

会有人反馈为啥不存储数据库,一步到位,流程也好操作?!

这是根据业务场景来,根据实际场景使用。如果是应用于集群环境,需自行修改配置

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值