在大约8年之后,我目前正重新开始用Java+Spring进行编码。在过去的8年里,我花在编码上的时间明显减少了,因为我现在进入了领导岗位,使我不再写代码。尽管如此,我还是需要了解一定程度的编码,尤其是在Java世界,因为我发现我的大部分项目都是用这种语言,除非我熟悉编码,否则我无法有效地帮助我的团队。自从我停止编码以来,已经发生了很多变化,我正在重新学习一切。这是我将写的许多文章中的第一篇,随着我对新事物的了解,我将写下这些文章。另外,我正在建立一个应用程序,更多的是来自我个人的成果。我一般不能花一致的时间,这使我可以花更多的时间学习,而不是努力满足实际生活中客户项目的最后期限。
在这篇文章中,我将谈论如何在Spring Boot应用程序中使用外部化配置。
1.概述
我们将使用Spring Boot的默认设置来创建一些配置,并在我们的应用程序中读取这些配置。我们还将研究一种简单的键值方式来设置属性和基于YAML的配置。
我更喜欢使用YAML,从现在开始,我将只使用YAML为基础的设置。
2.初始设置
在实施过程中,我注意到我最终被要求使用spring-boot-configuration-processor依赖关系。否则,我就会得到一个错误,代码无法编译。在我的研究中,我并没有找到很多关于为什么需要这样做的原因,但是添加这个依赖关系为我解决了这个问题。
我添加的第二个依赖项是Actuator,它为我们提供了一些令人兴奋的工具。这是不必要的,但如果你想调试你的属性并找到更多的配置来工作,我建议你也添加这个:
<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>
3.设置配置文件
下面的代码是application.properties文件,这是你在Spring Boot中得到的默认格式:
# This is to expose all the endpoints for Actuator. use * for all ONLY in DEV
management.endpoints.web.exposure.include=*
# Custom Properties
bungie.rootPath="https://www.bungie.net/Platform"
bungie.apiKey=000999888111
以下是YAML格式的相同属性:
bungie:
rootPath: "https://www.bungie.net/Platform"
apiKey: 000999888111
4.创建将读取这些配置的Bean
现在我们已经创建了这些属性,在读取这些属性时,我们需要考虑两种使用情况:
- 读取单一属性- 在这种情况下,我们可能需要创建一个需要读取一次的属性,或者不能与任何其他属性归为一类。在这种情况下,你可以使用@Value注解来读取它。
- 读取一组属性--在我们的例子中,我们已经在 "bungie "类别下确定了两个分组的属性。这是我喜欢的创建属性的方式。我不喜欢有无主的属性,因此我们将只看到如何设置这些属性。下面的例子将显示我们创建一个Java Bean/Configuration,它将能够读取我们的属性文件并填充对象。
package io.howtoarchitect.destinyclanwars.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties("bungie")
@Getter @Setter
public class BungieClientSettings {
private String rootPath;
private String apiKey;
}
如果你观察上面的代码块,你会注意到一些事情:
- 我们使用了
@Configuration,让Spring应用程序知道这是一个Bean,并且应该被初始化成这样 @Getter和 是来自Lombok包,给了我们默认的Getters和Setters。这些是强制性的,因为Spring应用程序总是需要这些获取器和设置器。@Setter@ConfigurationProperties是在这里做主要技巧的注解。它将浏览我们上下文中所有可用的属性,并搜索任何已被映射为用户 "bungie "的属性。一旦找到,这个注解将映射YAML/Properties文件的值,并将它们添加到我们的字符串中。
5.消耗属性
一旦你完成这些设置,最后一步就是在我们的应用程序中读取这些属性。我们将在另一个Spring Bean/服务中读取这些属性:
package io.howtoarchitect.destinyclanwars.bungieclient;
import io.howtoarchitect.destinyclanwars.config.BungieClientSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class BungieClient {
private static WebClient client;
@Autowired
private BungieClientSettings bungieClientSettings;
public WebClient getDefaultClient() {
client = WebClient.builder()
.baseUrl(bungieClientSettings.getRootPath())
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader("X-API-KEY", bungieClientSettings.getApiKey())
.build();
return client;
}
}
你会注意到,我已经把BungieClientSettings 作为一个@Autowired 依赖关系。这就在我的类中注入了Bean,当我需要访问这些属性时,我所需要做的就是bungieClientSettings.getAPIKey() 和bungieClientSettings.getRootPath() 。
结论
这就是你需要做的,将你的属性外部化。这在早期是很重要的,因为如果你不这样做,你最终会有许多分散在类中的属性,并且在多个环境中移动会变得很困难。
在接下来的几篇文章中,我们将看一下:
- 如何使用基于环境的配置:在我的案例中,我将有不同的密钥用于开发和生产,我将能够处理同样的问题。
- 使用Spring的云配置服务器,这将允许我们把配置集中到1个项目中,也能够在不部署代码的情况下交换设计(配置即代码模式)。
- 最后,我们将研究如何通过加密来保护其中的一些属性。例如,我的
apiKeys,需要进行确认。我在给出的样本中使用了随机值,但在我的应用中,我需要密钥是有效的,而且不能通过GITHUB repo的纯文本文件暴露。