简介
本文介绍Spring Cloud的@RefreshScope动态刷新的注意事项。
不用@RefreshScope也能动态刷新
Spring Cloud的默认实现了动态刷新,不加@RefreshScope就能实现动态更新。方法如下:
法1:ApplicationContextHolder.getContext().getEnvironment().getRequiredProperty(key);
ApplicationContextHolder见:SpringBoot-静态获得Bean的工具类 – 自学精灵
法2:使用@ConfigurationProperties将配置放到类里边去
@ConfigurationProperties的用法见:SpringBoot-用类表示yml配置文件的值 – 自学精灵
原理
配置属性有ConfigurationPropertiesRebinder这个监听器,监听EnvironmentChangeEvent事件。当发生EnvironmentChange事件后,会刷新Environment,然后重新构造配置类对象。
@RefreshScope会失效
我们经常用@Value来使用配置,此时类上要加@RefreshScope。但是,@RefreshScope结合@Value这种用法,在一些场景下,自动刷新会失效!
会失效的场景
场景1:使用@RefreshScope的类必须是注入到容器中的bean,否则无效。
场景2:假如A组件注入B组件,B组件上使用了@RefreshScope并使用@Value获取配置,那么A组件上必须也加上@RefreshScope,否则无法实现动态刷新。
场景3:@RefreshScope 不能用在 @Scheduled、Listener、Timmer等类上,会有问题。以Scheduled为例:如果使用了@Scheduled的类里用@Value引入了配置,当配置中心修改了这个配置时,这个定时调度会失效(不再执行)。
解决方案
注意事项
- @RefreshScope作用的类,不能是final类,否则启动时会报错。
- 如果类里的方法有@XxlJob,不要使用@RefreshScope,否则定时任务报错:job handler [xxx] not found.(这个是XXL-JOB的问题,一直没解决)
静态变量用@RefreshScope的坑
代码
Controller
package com.knife.example.business.order.core.test; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController public class TestController { @Autowired private TestUtil testUtil; @GetMapping("test") public String test() { System.out.println(TestUtil.findConfig()); testUtil.nothing(); System.out.println(TestUtil.findConfig()); return "success"; } }
工具类
package com.knife.example.business.order.core.test; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Component; @Component @RefreshScope public class TestUtil { private static String name; @Value("${custom.name}") public void setName(String name) { TestUtil.name = name; } public static String findConfig() { return name; } public void nothing() { } }
配置中心
测试
结果:
hello hello
修改配置中心的值,改为:
再次测试,访问:http://localhost:9012/test
结果
hello hi
原因分析
动态刷新成功时,仅仅是再创建类一个代理对象,并清除了实际对象的缓存;再次通过代理对象来使用时,才会触发创建一个新的实例对象,此时才会更新配置的值。
请先
!