spring cloud:config-server中@RefreshScope的"陷阱"
spring cloud的config-serfver主要用于提供分布式的配置管理,其中有一个重要的注解:@RefreshScope,如果代码中需要动态刷新配置,在需要的类上加上该注解就行。但某些复杂的注入场景下,这个注解使用不当,配置可能仍然不动态刷新,比如下面的场景:
1. 先定义一个配置类(假设这里面定义了一个apiUrl,表示调用的api地址)
@Component
@ConfigurationProperties(prefix = "demo.app")
@Data
@RefreshScope
public class DemoServiceAppConfig {
/**
* api调用地址
*/
private String apiUrl = "";
}
对应的yml配置类似:
demo:
app:
apiUrl: "http://11111.com/xxxxx"
2. 然后定义一个工具类,用于封装调用外部api
@Data
@RefreshScope
public class TestUtil {
private String apiUrl;
public void callApi() {
System.out.println("apiUrl:" + apiUrl);
}
}
3. 为了避免1中的配置类,与2中的工具类强耦合,搞一个bean注入容器把他们关联起来
@Component
@RefreshScope
public class BeanContainer {
@Autowired
DemoServiceAppConfig appConfig;
@Bean
private TestUtil testUtil() {
TestUtil testUtil = new TestUtil();
testUtil.setApiUrl(appConfig.getApiUrl());
return testUtil;
}
}
4 最后来一个Controller测试下
@RestController
@RefreshScope
@Api(consumes = "application/json",
produces = "application/json",
protocols = "http",
basePath = "/")
public class PingController extends AbstractController {
@Autowired
DemoServiceAppConfig appConfig;
@Autowired
TestUtil testUtil;
@RequestMapping(value = "/test", method = {RequestMethod.GET, RequestMethod.POST})
public String test() {
return "config.apiUrl=>" + appConfig.getApiUrl() + "<br/>testUtil.apiUrl=>" + testUtil.getApiUrl();
}
}
注:上面所有这些类,都加了@RefreshScope标签。
跑起来,效果如下:
然后把yml文件改下,然后push到git上,再curl -X POST http://localhost:7031/refresh 刷一把配置
可以看到,通过testUtil调用的方法中,取到的apiUrl值仍然是旧的,并没有动态刷新!
正确姿势如下:
最后一个问题,@RefreshScope作用的类,不能是final类,否则启动时会报错,类似下面这堆:
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class TestUtil at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:565) ~[spring-core-4.3.9.RELEASE.jar:4.3.9.RELEASE]
从出错信息上看,底层应该是使用cglib进行增强,需要在TestUtil下派生子类。
然后,由cglib又引出了更一个坑,如果在一些web核心组件相关的config上误加了@RefreshScope, 比如下面这样:
@Bean
@RefreshScope
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
这里面有一个org.springframework.web.cors.CorsConfiguration配置类,加了@RefreshScope后,org.springframework.web.filter.GenericFilterBean#init 这个核心bean的init就会报错,要么应用启不起来,要么请求时报内部错误。
- 用深度学习keras的cnn做图像识别分类,准确率达97%
- 短信发送接口被恶意访问的网络攻击事件(三)定位恶意IP的日志分析脚本
- job处理缓慢的性能问题排查与分析(r4笔记第18天)
- 京东商品评论情感分析:数据采集与词向量构造方法
- springboot开启access_log日志输出
- 完美的执行计划导致的性能问题(r4笔记第17天)
- 解决Docker容器时区及时间不同步的问题
- 移动端测试方案--sptt
- 服务端事件EventSource揭秘
- 让docker中的mysql启动时自动执行sql文件
- 通过执行计划中的CONCATENATION分析sql问题(r4笔记第16天)
- 《小美好》短评文本情感分析+生成词云
- 通过shell定制dbms_advisor.quick_tune(r4笔记第15天)
- 跨浏览器tab页的通信解决方案尝试
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 快速学习-开发你的作业
- 理解Spring中的IoC和DI
- 快速学习-Saturn性能测试报告
- Java源码系列1——ArrayList
- 【Kubernetes】自定义资源CRDs不支持fieldselector
- Cypress系列(48)- and() 命令详解
- Java源码系列2——HashMap
- 快速学习-Saturn Console部署
- MySQL的各种日志
- 本地机器如何访问服务器上的docker容器内的tensorboard?
- MySQL是如何实现可重复读的?
- Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?
- 如何理解被 protected 修饰的成员变量?
- 重学数据结构(五、串)
- python boto和boto3操作bucket