springboot动态加载配置文件 | 张扎瓦的博客

springboot动态加载配置文件

本文介绍了使用springboot自动刷新配置文件的办法


前言

在使用springboot时,读取配置文件很方便,但每次修改完配置后,都需要重启。如果是线上环境,是不可能频繁重启服务的,那么有没有办法不重启,就能使配置文件生效呢?

方法1

不使用springboot提供的读取配置文件的方法,自己写一个工具类来定时读取配置文件。这个代码比较简单,就不在这里贴了,这种思路虽然能实现,但感觉并不怎么好,最好还是能利用springboot自带的一些特性去做。

方法2

其实springboot本身是支持自动刷新配置文件的,只不过是需要借助springcloud来做。springcloud有配置中心组件,可以达到这个目的,而且功能非常强大,既可以刷新本地配置,又可以刷新远程配置文件,还可以结合springcloud-bus消息总线和mq,实现动态刷新,此处我们只演示本地配置文件刷新。

pom.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>

<!-- spring cloud -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<!-- 监控 -->
<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>

<!-- 简化java bean -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<!-- httpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.10</version>
</dependency>

</dependencies>

spring-boot-starter-actuator提供服务健康检查和暴露内置的url接口。

spring-cloud-starter-config提供动态刷新的一些支持和注解。

application.properties

在配置文件中,加入以下配置项,来模拟读取配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#端口号
server.port=10010

#=============================
#活跃线程数
thread.pool.corePoolSize=20
#最大线程数
thread.pool.maxPoolSize=40
#有效时间
thread.pool.keepAliveSeconds=300
#线程池缓存队列大小
thread.pool.queueCapacity=50
#==============================

#暴露内置的刷新配置文件url,这个必须写,否则无法刷新配置文件
management.endpoints.web.exposure.include=refresh

注意:spring-boot-starter-actuator为了安全起见,默认将大部分内部接口隐藏起来了,需要时,可以通过

management.endpoints.web.exposure.include

management.endpoints.web.exposure.exclude

这两个配置项来进行配置,

当需要暴露所有的内部接口时,可以这样配置:

management.endpoints.web.exposure.include=*

此处我们只需要暴露出动态刷新的接口refresh就可以进行动态刷新,完整的url规则为:

http://地址/端口号/服务上下文/actuator/refresh

创建类来读取配置内容

springboot既支持@Value的方式读取,也可以通过@ConfigurationProperties的方式读取,下面我们来演示这两种方式。

Value方式

1
2
@Value("${thread.pool.corePoolSize}")
private int corePoolSize;

很简单,直接在需要读取的类中,写上就可以了。

ConfigurationProperties方式

这个方式需要单独创建一个类,类中的属性名需要和配置文件名称一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "thread.pool")
public class ThreadConfig {

/**
* 活跃线程数
*/
private int corePoolSize;

/**
* 最大线程数
*/
private int maxPoolSize;

/**
* 有效时间
*/
private int keepAliveSeconds;

/**
* 线程池缓存队列大小
*/
private int queueCapacity;

}

因为我写的配置文件中,有公共的前缀thread.pool,所以此处需要写上prefix = "thread.pool"

@Data这个注解是lombok提供的注解,用于自动生成get/set等模板方法

@RefreshScope表示开启配置文件刷新

创建controller

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class TestA {
@Resource
private ThreadConfig threadConfig;

@RequestMapping("/a")
public int getCore() {
return threadConfig.getCorePoolSize();
}

}

配置启动类

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@ConfigurationPropertiesScan
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

开始测试

我们使用postman来测试,可以看到当前的值是20

接下来将thread.pool.corePoolSize的值改为100,然后使用POST请求调用刷新配置接口。在当前项目中,这个接口的地址为:http://localhost:10010/actuator/refresh

注意:这个接口只能使用 POST 请求调用

调用成功后,如下图所示:

我们再次请求 /a 这个接口,查看结果是否已经刷新。

可以看到值已经更新成修改后的值。

自动刷新

到目前为止,我们已经实现了配置文件不重启服务刷新,但每次改完配置后,手动调一次刷新接口也比较麻烦,接下来继续改造,做成自动刷新。

我们可以使用定时任务来进行自动刷新,每隔10秒自动调一次刷新接口,这样就不用每次改完手动刷新了。

增加配置项

1
2
#刷新配置文件地址
refresh.url=http://localhost:${server.port}/actuator/refresh

创建定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Slf4j
@Component
public class RefreshProperties {

@Value("${refresh.url}")
private String refreshUrl;

/**
* 每10秒刷新一次配置文件
*/
@Scheduled(fixedDelay = 10 * 1000)
public void refresh() {
log.debug("------------------------- 开始刷新配置文件内容 -------------------------");
String post = HttpUtils.post(refreshUrl);
log.debug("刷新配置文件接口返回内容:{}", post);
}

}

启动类增加注解

在启动类上,增加@EnableScheduling注解,支持定时任务,这样整个功能就完成了。

测试

当我们修改了配置项时,隔上10秒,控制台会打印如下信息

表明自动刷新完成

特别提示

如果项目启动后报:

1
2
Connect Timeout Exception on Url - http://localhost:8888. Will be trying the next url if available
Could not locate PropertySource: I/O error on GET request for "http://localhost:8888/application/default": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect

这两个警告,你需要增加一个配置文件bootstrap.properties,并加入如下配置项:

1
2
#关闭加载远程配置文件
spring.cloud.config.enabled=false

因为spring-cloud-starter-config默认会加载远程的配置文件,关掉就可以了。

如果我的文章对您有所帮助,不妨打赏一杯豆浆以资鼓励(○` 3′○)