前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring cloud:config-server中@RefreshScope的"陷阱"

spring cloud:config-server中@RefreshScope的"陷阱"

作者头像
菩提树下的杨过
发布2018-01-18 16:23:37
2.8K0
发布2018-01-18 16:23:37
举报

spring cloud的config-serfver主要用于提供分布式的配置管理,其中有一个重要的注解:@RefreshScope,如果代码中需要动态刷新配置,在需要的类上加上该注解就行。但某些复杂的注入场景下,这个注解使用不当,配置可能仍然不动态刷新,比如下面的场景:

1. 先定义一个配置类(假设这里面定义了一个apiUrl,表示调用的api地址)

代码语言:javascript
复制
@Component
@ConfigurationProperties(prefix = "demo.app")
@Data
@RefreshScope
public class DemoServiceAppConfig  {
    /**
     * api调用地址
     */
    private String apiUrl = "";
}

 对应的yml配置类似:

代码语言:javascript
复制
demo:
  app:
    apiUrl: "http://11111.com/xxxxx"

2. 然后定义一个工具类,用于封装调用外部api

代码语言:javascript
复制
@Data
@RefreshScope
public class TestUtil {

    private String apiUrl;

    public void callApi() {
        System.out.println("apiUrl:" + apiUrl);
    }
}

3. 为了避免1中的配置类,与2中的工具类强耦合,搞一个bean注入容器把他们关联起来

代码语言:javascript
复制
@Component
@RefreshScope
public class BeanContainer {

    @Autowired
    DemoServiceAppConfig appConfig;

    @Bean
    private TestUtil testUtil() {
        TestUtil testUtil = new TestUtil();
        testUtil.setApiUrl(appConfig.getApiUrl());
        return testUtil;
    }

}

4 最后来一个Controller测试下

代码语言:javascript
复制
@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值仍然是旧的,并没有动态刷新!

正确姿势如下:

image.png
image.png

最后一个问题,@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, 比如下面这样:

代码语言:javascript
复制
    @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就会报错,要么应用启不起来,要么请求时报内部错误。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-12-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档