前文提到:
当配置中心更改配置之后,有两种方式可以动态刷新Bean的配置变量值
- 向上下文发布一个RefreshEvent事件
- Endpoint方式,Http访问/actuator/refresh(springboot2.0之前为/refresh,springboot2.0之后默认没有开启refresh端点,需配置)
不管是什么方式,最终都会调用ContextRefresher这个类的refresh方法。
现在我们通过第二种Endpoint方式来感受一下:
新建一个SpringBoot工程引入如下依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控+refresh配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
(1)spring-cloud-starter-config是为了实现刷新配置
(2)spring-boot-starter-actuator是为了暴露修改/刷新配置的接口
(3)spring-boot-starter-web是为了可以访问暴露的修改/刷新配置的接口
修改application.properties
server.port=8080
#暴露所有endpoints
management.endpoints.web.exposure.include=*
@RestController
@RefreshScope
public class TestController {
@Value("${server.port}")
private String port;
@GetMapping("/test")
public String port(){
return port;
}
}
随后启动项目
可以看到暴露了17个以/actuator为前缀的endpoint,其中就会有一个叫做/actuator/refresh的接口
第一次请求:
修改编译过后的文件也就是target目录下的application.properties改为8081
随后通过postman请求/actuator/refresh,因为/actuator/refresh接口为post,可以看到返回的是修改后的key
然后再次刷新浏览器可以发现已经改为8081了
当我们请求/actuator/refresh的时候,断点会进入这里,所以最终会调用ContextRefresher的refersh的方法,验证了我们上面的结论,此方法也就是返回修改后的key。
这里整个@RefreshScope 的原理就介绍完了。
下面对SpringBoot如何自动刷新配置的原理进行总结:
首先要想实现配置自动刷新,类上需要标注一个@RefreshScope的注解,被此注解标注的Bean其作用域scope会被定义成refresh,这类Bean的创建逻辑会走单独的一个逻辑,并且最终被一个Map缓存下来,当配置被更改后,通过触发一个refresh操作,会把当前Map清空,这些Bean就会重新被IOC容器创建一次,使用最新的外部化配置的值注入类中,达到热加载新值的效果。