前言
到目前为止,每个人都知道可配置的应用程序属性文件(properties, yaml, txt, json) 应该放置在已部署的构件(war、jar、ear)之外。
如果只是为了更改配置文件,大家都不想发布新版本的应用程序/服务。我们希望开发、测试、生成环境等都能实现实时刷新应用程序属性。
幸运的是,有很多选项可以将您的配置外部化,Spring Boot 甚至支持这种开箱即用的逻辑。
这些解决方案中的大多数都需要重新启动应用程序/服务,但本文将演示如何忽略此限制。
配置服务
首先,本文展示一种如何外部化应用程序属性并从 git 管理它们的方法。
Git 是有意义的,因为它会跟踪任何更改。你可以看到谁在任何给定的时间点改变了什么!
为此,本文先创建了一个(微)服务。我们称之为配置服务。
将以下依赖项添加到配置服务。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>1.1.3.RELEASE</version>
</dependency>
</dependencies>
将@EnableConfigServer注释添加到 Spring 引导入口点。
此注释将负责配置服务器的所有配置。
非常简单方便!
package com.github.xiaomian;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServiceApplication.class, args);
}
}
在 “application.properties”属性文件中指定 git 存储库的路径。
server.port=8888
spring.cloud.config.server.git.uri=/tmp/example-properties
创建一个新的 git 项目,其中包含你的自定义属性。
mkdir /tmp/example-properties
cd /tmp/example-properties
git init
echo foo.bar=Hi! > application.properties
git add application.properties
git commit -m 'Add foo.bar property'
就这样基本配置服务已准备就绪!
示例服务
现在创建一个示例服务。
将以下依赖项添加到示例服务。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<version>1.1.3.RELEASE</version>
</dependency>
定义一个返回示例属性值的示例控制器。
package com.github.xiaomian;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class ExampleServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleServiceApplication.class, args);
}
@RestController
class ExampleController {
@Value("${foo.bar}")
private String value;
@RequestMapping
public String sayValue() {
return value;
}
}
}
如果启动应用程序,则应在日志文件中看到以下消息。
INFO 60864 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
INFO 60864 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=application, profiles=[default], label=master, version=1e4c80569fc05655903c12c6087ffdf797a0c71e
INFO 60864 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource [name='configService', propertySources=[MapPropertySource [name='/tmp/example-properties/application.properties']]]
现在可以调用服务,并查看结果。
curl -v http://localhost:8080
* Rebuilt URL to: http://localhost:8080/
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200
< X-Application-Context: application
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 3
< Date: Sat, 20 Aug 2016 11:41:12 GMT
<
* Connection #0 to host localhost left intact
Hi!%
服务运行正常,那么如何动态更改此属性?
理论上,您可以刷新应用程序上下文,但是不建议这样做。Spring提供了一个注释,将Bean标记为可刷新。
通过添加Spring acuator,就可以实现即时刷新这些Bean对象。
将spring-boot-starter-actuator添加到示例服务中。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
将 @RefreshScope 注解添加到包含需要可重新装入的属性的 Bean 中。
package com.github.xiaomian;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class ExampleServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleServiceApplication.class, args);
}
@RestController
@RefreshScope
class ExampleController {
@Value("${foo.bar}")
private String value;
@RequestMapping
public String sayValue() {
return value;
}
}
}
现在再测试一下!
#修改配置
echo foo.bar=Change! > application.properties
git add application.properties
git commit -m 'A change'
配置服务将自动检测提交并开始提供新值。但是,我们希望在示例服务中看到更改。为此,我们必须调用actuator已添加的刷新端点/refresh。
curl -X POST http://localhost:8080/refresh
["foo.bar"]%
对示例服务的调用现在将包含我们的新值。
curl -v http://localhost:8080
* Rebuilt URL to: http://localhost:8080/
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200
< X-Application-Context: application
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 7
< Date: Sat, 20 Aug 2016 11:54:10 GMT
<
* Connection #0 to host localhost left intact
Change!%
结论
通过添加一些简单但功能强大的注释,就可以从 git 轻松管理应用程序的属性。
刷新机制使您可以轻松动态应用属性更改。
但是,配置服务最好主动将其新值推送到其客户端。Nacos就是通过监听到有属性值发生了变更,主动拉取配置信息,通过事件机制刷新属性!后续会进一步通过源码导读带大家了解nacos是如何实现实时刷新应用程序属性!