spring cloud的config-serfver主要用於提供分佈式的配置管理,其中有一個重要的註解:@RefreshScope,若是代碼中須要動態刷新配置,在須要的類上加上該註解就行。但某些複雜的注入場景下,這個註解使用不當,配置可能仍然不動態刷新,好比下面的場景:javascript
1. 先定義一個配置類(假設這裏面定義了一個apiUrl,表示調用的api地址)java
@Component @ConfigurationProperties(prefix = "demo.app") @Data @RefreshScope public class DemoServiceAppConfig { /** * api調用地址 */ private String apiUrl = ""; }
對應的yml配置相似:git
demo: app: apiUrl: "http://11111.com/xxxxx"
2. 而後定義一個工具類,用於封裝調用外部apiweb
@Data @RefreshScope public class TestUtil { private String apiUrl; public void callApi() { System.out.println("apiUrl:" + apiUrl); } }
3. 爲了不1中的配置類,與2中的工具類強耦合,搞一個bean注入容器把他們關聯起來spring
@Component @RefreshScope public class BeanContainer { @Autowired DemoServiceAppConfig appConfig; @Bean private TestUtil testUtil() { TestUtil testUtil = new TestUtil(); testUtil.setApiUrl(appConfig.getApiUrl()); return testUtil; } }
4 最後來一個Controller測試下json
@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標籤。api
跑起來,效果以下:app
而後把yml文件改下,而後push到git上,再curl -X POST http://localhost:7031/refresh 刷一把配置cors
能夠看到,經過testUtil調用的方法中,取到的apiUrl值仍然是舊的,並無動態刷新!curl
正確姿式以下:
最後一個問題,@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就會報錯,要麼應用啓不起來,要麼請求時報內部錯誤。
最後,還有一個要注意的坑,好比:
abc: "xxx"
若是yml文件中有一個這樣的屬性,改爲:
abc: ""
即變成空後,就算再curl -X POST http://.../refresh 接口,代碼中拿到的值,仍然是xxx,建議若是要讓一個屬性值失效,能夠約定一個特定值,好比
abc:"NULL"
而後代碼中用「NULL」來判斷.