Spring Boot Microservices将配置开发为服务

为什么我们需要配置服务? (Why do we need Config Service?)

In the previous exercise, we took the example of an e-commerce domain and developed a basic microservice — Product Catalog Service. This service used MongoDB to store and retrieve product details. We provided the MongoDB connection configuration in the “application.properties”, which was bundled with the code. (Do check out the code for Product Catalog Service to revise what we developed previously, on this series)

在上一个练习中,我们以电子商务领域为例,并开发了一个基本的微服务- 产品目录服务 。 该服务使用MongoDB来存储和检索产品详细信息。 我们在“ application.properties”中提供了MongoDB连接配置,该配置与代码捆绑在一起。 (请检查产品目录服务的代码 修改我们之前在本系列中开发的内容)

If we break down the e-commerce monolith system, it will lead to tens of microservices. Each of these services will have their configuration needs. With so many services co-existing, and each carrying multiple instances, the configuration becomes one of the key challenges. With typical applications(monolith), we could have achieved —

如果我们破坏电子商务整体系统,它将导致数十种微服务。 这些服务中的每一个都有其配置需求。 由于有这么多服务共存,并且每个服务都带有多个实例,因此配置成为关键挑战之一。 通过典型的应用(整体式),我们可以实现-

  1. configuration bundled with the archive

    归档捆绑在一起的配置

  2. configuration passed through environment variables

    通过环境变量传递的配置

  3. configuration passed through an external file

    通过外部文件传递的配置

With microservices, the first two options are difficult to achieve, as it will lead to multiple copies of the configuration. Even if we need to change a single configuration, we will be forced to update all the services, their instances, or the environment variables, which seems a bit impractical. The worst-case scenario is when the configuration is bundled with the Microservice. We need to make the change in source code, which means it goes through the whole development cycle before it's updated on the production environment. This could take days. In the meantime, our services will function with inconsistent configurations.

对于微服务,前两个选项很难实现,因为它将导致配置的多个副本。 即使我们需要更改单个配置,也将被迫更新所有服务,它们的实例或环境变量,这似乎有些不切实际。 最坏的情况是,当配置与微服务捆绑在一起。 我们需要对源代码进行更改,这意味着它需要经历整个开发周期才能在生产环境中进行更新。 这可能需要几天的时间。 同时,我们的服务将以不一致的配置运行。

To resolve it, we must define configuration — externally, it should be centralized and loosely coupled. A single source for configuration will ensure consistency among all the services. Can we keep it as a common external file?

要解决它, 我们必须定义配置-在外部,它应该是集中的并且松散耦合的 。 单一的配置来源将确保所有服务之间的一致性。 我们可以将其保留为通用外部文件吗?

Different microservices will be deployed in multiple systems, and the systems could be placed anywhere — a different region, a different network. There is no guarantee that the file protocol will work in this case. Also what happens if we decide to move the location of these files. We will run into the same problem again.

不同的微服务将部署在多个系统中,并且这些系统可以放置在任何地方-不同的区域,不同的网络。 在这种情况下,不能保证文件协议会起作用。 如果我们决定移动这些文件的位置,也会发生什么。 我们将再次遇到相同的问题。

We must expose the configuration through an independent Configuration Service where configurations can be read and updated remotely. It can function like any other Microservice.

我们必须通过独立的配置服务公开配置,在该服务中可以远程读取和更新配置。 它可以像其他任何微服务一样运行。

配置服务的外观如何? (How does the Config Service look like?)

As we agree on the fact that we need a centralized config service, let's see how it fits into the ecosystem.

当我们同意需要集中式配置服务这一事实时,让我们看看它如何适应生态系统。

Image for post
Microservices Ecosystem — Config Service
微服务生态系统—配置服务

All the services and their multiple instances will consume the centralized config service to get the configurations. Spring-based microservices will typically consume the service with the help of a config client. Our Config Service will function like any other microservice, which in turn will make it more independent and stand-alone. Also, our Config Service will use a source (Config Repo) to keep the configurations (files). The source could be any mode of storage for e.g. Git Repository, Database, File System, etc.

所有服务及其多个实例将使用集中式配置服务来获取配置。 基于Spring的微服务通常会在配置客户端的帮助下使用该服务。 我们的Config服务将像其他任何微服务一样运行,从而使它更加独立和独立。 另外,我们的Config Service将使用源( Config Repo )保留配置(文件)。 源可以是任何存储模式,例如Git存储库,数据库,文件系统等。

Lets list down the fundamental needs(or features) of our Config Service

让我们列出配置服务的基本需求(或功能)

  • Shared configurations (for e.g. database host address)

    共享配置(例如,数据库主机地址)

  • Service specific configurations (for e.g. database name)

    服务特定的配置(例如,数据库名称)

  • Configurations for different environments (for e.g. dev, test, prod)

    不同环境的配置(例如,开发,测试,生产)

  • Configuration is remotely accessible

    可以远程访问配置

  • Configuration is protected

    配置受保护

  • Configuration is updated real time

    配置实时更新

Fortunately “spring cloud-config” supports all the features listed above. The next sections will focus on — How to make it work? We will develop a sample “Config Service” and a sample “Config Client” as part of this exercise. Apart from Spring Cloud, we will be using Spring Boot, MongoDB, and Git as the supporting technologies. Also, ensure that you have JDK 11 and Maven 3.x installed on your machines.

幸运的是,“ spring cloud-config”支持上面列出的所有功能。 下一节将重点讨论- 如何使其工作? 在本练习中,我们将开发一个示例“ Config Service”和一个示例“ Config Client”。 除了Spring Cloud之外 ,我们还将使用Spring BootMongoDBGit作为支持技术。 另外,请确保在计算机上安装了JDK 11Maven3.x

开发配置服务 (Developing Config Service)

配置服务 (Config Service)

As discussed earlier our config service is just another Microservice. We will use spring boot initializer to get the skeleton code for it. Please note that we need to add “spring config server” as a dependency. Leave other values as the default ones. I did update group and artifact values as below, its optional though.

如前所述,我们的配置服务只是另一个微服务。 我们将使用Spring Boot初始化程序来获取其框架代码。 请注意,我们需要添加“ spring config server”作为依赖项。 将其他值保留为默认值。 我确实按以下方式更新了工件值,尽管它是可选的。

Image for post

Click on GENERATE. You will be asked to download the application archive. Download and unbundle the archive at your location. Open theConfigServerApplication.java and add @EnableConfigServer annotation to the class. This will run our Spring Boot application as a config server.

单击生成 。 系统将要求您下载应用程序存档。 在您所在的位置下载存档文件并取消捆绑。 打开ConfigServerApplication.java并将@EnableConfigServer批注添加到该类。 这将把我们的Spring Boot应用程序作为配置服务器运行。

package com.example.microservices.configserver;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;@SpringBootApplication@EnableConfigServer
public class ConfigServerApplication {public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}}

Config service is designed in such a way that it can support the configurations stored in multiple modes including the file system, vault, git, redis, aws s3 and many more. The default option comes with Git, and we will stick to it for our exercise as well.

配置服务的设计方式使其可以支持以多种模式存储的配置,包括文件系统,保管库,git,redis,aws s3等。 Git附带了默认选项,我们也会在练习中坚持使用它。

配置仓库 (Config Repo)

To define the source for our Config Service, we need to create a new Git repository — config_repo. For our exercise purpose, we will do this in our local machine. You need to install git, if not already installed.

要定义Config Service的源,我们需要创建一个新的Git存储库config_repo 。 出于锻炼目的,我们将在本地机器上执行此操作。 您需要安装git(如果尚未安装)。

Please refer the commands below. We are initializing a git repository and then adding a sample configuration, application.properties file, in it. I used the command line to do it ( echo…) but you can use your favourite editor to edit application.properties.

请参考以下命令。 我们正在初始化git存储库,然后在其中添加示例配置application.properties文件。 我使用命令行来做到这一点( echo… ),但是您可以使用自己喜欢的编辑器来编辑application.properties

mkdir config_repo
git init
echo sample.config.key:sample.config.value > application.properties
git add application.properties
git commit -m "adding default configuration"

链接“ Config Repo”和“ Config Service” (Linking “Config Repo” with “Config Service”)

Now our source config_repo is ready. Its time to connect this to our Config Service. Open the service codebase in your favorite editor and update config_service/src/main/resources/application.properties to add the reference of config_repo

现在我们的源文件config_repo已经准备好了。 是时候将其连接到我们的Config Service了 在您喜欢的编辑器中打开服务代码库,并更新config_service/src/main/resources/application.properties以添加config_repo的引用

application.properties

application.properties

server.port: 8888spring.cloud.config.server.git.uri: file://${user.home}/codebase/config-repo

访问样本配置 (Accessing sample configuration)

We also made one more change here — updating the port. As we will be testing on our localhost environment, we must update the port, or else it will create a conflict with other services. We are now ready to access our sample configuration. Go to the browser and access the configuration with the localhost URL — http://localhost:8888/application/default. This will return a response similar to the one below. The highlighted part is the configuration we saved.

我们还在此处进行了另一项更改-更新端口。 当我们要在本地主机环境上进行测试时,我们必须更新端口,否则它将与其他服务产生冲突。 现在,我们可以访问我们的样本配置。 转到浏览器并使用localhost URL( http:// localhost:8888 / application / default)访问配置。 这将返回与以下响应类似的响应。 突出显示的部分是我们保存的配置。

{
"name":"application",
"profiles":[
"default"
],
"label":null,
"version":"ac147db76119b4c5b2691cb2723955e45feed75d",
"state":null,
"propertySources":[
{
"name":"file:///Users/xxxxx/codebase/config-repo/application.properties","source":{
"sample.config.key":"sample.config.value"
}

}
]
}

Our config server is ready to function now. Let's see how we can make the Config Service more useful.

我们的配置服务器现在可以运行了。 让我们看看如何使Config Service更有用。

特定于服务的配置 (Service-specific configurations)

Configurations defined in application.properties are considered a default and it's shared across all the services. We can use it for service-specific configurations too. For this to achieve, let's add a new property file — product_catalog.properties in config_repo and move the ProductCatalogService configuration to this file. If you can’t recall this configuration, feel free to visit the first part of our series — Developing First Service.

application.properties中定义的配置被视为默认配置,并且在所有服务之间共享。 我们也可以将其用于特定于服务的配置。 为此,让我们在config_repo添加一个新的属性文件product_catalog.properties并将ProductCatalogService 配置移至该文件。 如果您不记得此配置,请随时访问我们系列的第一部分- 开发第一服务

#product_catalog.properties
spring.data.mongodb.uri=mongodb+srv://xxx-user:xxx-pwd@xxx-hostname/xxx-database

You must update the connection parameters as per your MongoDB instance. Once done, add this file to our config_repo .

您必须根据您的MongoDB实例更新连接参数。 完成后,将此文件添加到我们的config_repo

git add product_catalog.properties
git commit -m "adding service specific configuration"

That's it! The service-specific configuration is available through our Config Service now. You can access it through this URL — http://localhost:8888/product_catalog/default

而已! 特定于服务的配置现在可以通过我们的Config Service获得 。 您可以通过以下URL访问它-http:// localhost:8888 / product_catalog / default

更具体的配置 (More specific configurations)

You can also put the configurations for specific environments. For instance, we can create product_catalog-dev.properties for dev environment and product_catalog-prod.properties for the prod environment. Similarly, you can also access a particular version of the configuration (file). For more details on advanced configuration options, please visit https://cloud.spring.io/spring-cloud-config/reference/html/.

您还可以将配置用于特定环境。 例如,我们可以创建product_catalog-dev.properties的开发环境和product_catalog-prod.properties为督促环境。 同样,您也可以访问配置的特定版本(文件)。 有关高级配置选项的更多详细信息,请访问https://cloud.spring.io/spring-cloud-config/reference/html/

设置配置客户端 (Setting up Config Client)

Our Config Service is ready to serve configuration requests. With this approach, any microservice, developed in any technology, can pull the required configuration through HTTP protocol. It just needs an HTTP client API. Spring cloud config client makes it further easier by providing a client library which takes care of the boilerplate code. The library also facilitates Spring-based applications to consume the remote configuration during boot time.

我们的配置服务已准备就绪,可以处理配置请求。 通过这种方法,采用任何技术开发的任何微服务都可以通过HTTP协议提取所需的配置。 它只需要一个HTTP客户端APISpring Cloud config客户端通过提供负责样板代码的客户端库,使操作变得更加轻松。 该库还有助于基于Spring的应用程序在启动时使用远程配置。

Let's try to consume Config Service in our ProductCatalogService . We need to add spring-cloud-starter-config as a dependency to our service. Make the changes as shown below to your product_catalog/pom.xml

让我们尝试在我们的ProductCatalogService使用Config Service 。 我们需要添加spring-cloud-starter-config作为对我们服务的依赖。 对product_catalog/pom.xml如下所示的更改

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<properties>
<java.version>11</java.version><spring-cloud.version>Hoxton.SR7</spring-cloud.version>
</properties>
<dependencies>
... <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>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...
</project>

We need to define a new properties file — bootstrap.properties in product_catalog/src/main/resources . This will enable Product Catalog Service to start using Config Service for its configuration.

我们需要定义一个新的属性文件product_catalog/src/main/resources bootstrap.properties 。 这将使产品目录服务能够开始使用Config Service进行配置。

bootstrap.properties (bootstrap.properties)

spring.cloud.config.uri: http://localhost:8888
spring.application.name: product_catalog

The spring.cloud.config.uri tells where is the Config Service running. If we do not provide any value, it will by default assume this value(http://localhost:8888).

spring.cloud.config.uri告诉配置服务在哪里运行。 如果我们不提供任何值,则默认情况下将采用此值( http:// localhost:8888 )。

The spring.application.name tells what configuration our Product Catalog Service needs to refer, which in our case is product_catalog.properties. This field is also optional. If we do not provide it, it will try to pick up the configurations mentioned in application.properties, residing inside config_repo.

spring.application.name告诉我们产品目录服务需要引用什么配置,在本例中为product_catalog.properties 。 此字段也是可选的。 如果我们不提供它,它将尝试获取config_repo中位于application.properties提到的配置。

That's it. You can run the Product Catalog Service, and it's ready to pick the configuration from Config Service. You do not need product_catalog/src/main/resources/application.properties now.

而已。 您可以运行Product Catalog Service ,并且可以从Config Service中选择配置 您现在不需要product_catalog/src/main/resources/application.properties

动态更新配置 (Dynamically updating the configuration)

Now that we are able to create and consume Config Service, let's understand how we can ensure the configuration is updated dynamically. Let's try to illustrate through a small example.

现在我们可以创建和使用Config Service,让我们了解如何确保配置动态更新。 让我们尝试通过一个小例子来说明。

We are going to add a new feature to our ProductCatalogService , to sort the product list. This should be configurable though.

我们将向ProductCatalogService添加新功能,以对产品列表进行排序。 不过,这应该是可配置的。

package com.example.microservices.product_catalog;@RestController
public class ProductCatalogService {@Autowired
private MongoTemplate mongoTemplate;...@Value("${product.list.sort.column.default}")
private String defaultSortCol;
@GetMapping("/product")
public List < Product > getProductList() {
System.out.println("getting product list sorted by " + defaultSortCol);
Query query = new Query();
query.with(Sort.by(Sort.Direction.ASC, defaultSortCol));
return mongoTemplate.find(query, Product.class);
}
}

We have updated getProductList method to get the results sorted. The sort column can be configured through product.list.sort.column.default configuration. We are going to add this configuration in config_repo/product_catalog.properties

我们更新了getProductList方法来对结果进行排序。 可以通过product.list.sort.column.default配置来配置sort列。 我们将在config_repo/product_catalog.properties添加此配置

spring.data.mongodb.uri=mongodb+srv://xxx-user:xxx-pwd@xxx-hostname/xxx-?retryWrites=true&w=majorityproduct.list.sort.column.default=unitPrice #added

Let's commit the changes in the git repo. Visit http://localhost:8888/product_catalog/default and you will see the newly added configuration. If you run our Product Catalog Service, it will pick up this value and will return the product list sorted by unitPrice. What happens if I want to change the sort column value at run time?

让我们在git repo中提交更改。 访问http:// localhost:8888 / product_catalog / default ,您将看到新添加的配置。 如果您运行我们的产品目录服务 ,它将获取此值并返回按unitPrice排序的产品列表。 如果我想 在运行时 更改 排序列的值 ,会发生什么?

spring.data.mongodb.uri=mongodb+srv://xxx-user:xxx-pwd@xxx-hostname/xxx-?retryWrites=true&w=majorityproduct.list.sort.column.default=title #added

If you visit http://localhost:8888/product_catalog/default, you will see the updated configuration. But if you visit — http://localhost:8080/product/ to get the product list, it will still be sorted based on unitPrice only, and not on title . This is because the configuration is not updated automatically by the config clients, in our case — Product Catalog Service. One option is to restart the service, but it's not possible when multiple service instances are running.

如果您访问http:// localhost:8888 / product_catalog / default ,则会看到更新的配置。 但是,如果您访问http:// localhost:8080 / product /以获得产品列表,则仍将仅基于unitPrice而不是title对其进行排序。 这是因为配置客户端不会自动更新配置,在本例中为产品目录服务。 一种选择是重新启动服务,但是当多个服务实例正在运行时,这是不可能的。

To deal with this, spring cloud config provides — @RefreshScope annotation. We must use this annotation for the bean we want to refresh. In our case, we will apply this annotation on ProductCatalogService

为了解决这个问题,Spring Cloud配置提供了@RefreshScope注释。 我们必须对要刷新的bean使用此批注。 在我们的情况下,我们将在ProductCatalogService上应用此注释

@RestController@RefreshScope
public class ProductCatalogService { @Autowired
private MongoTemplate mongoTemplate; ...}

Also, we need to add spring-boot-starter-actuator dependency. This helps in getting the runtime information of service instances including health, environment, etc. Along with this, it also provides an endpoint actuator/refresh on spring boot application to refresh the bean configuration.

另外,我们需要添加spring-boot-starter-actuator依赖项。 这有助于获取服务实例的运行时信息,包括运行状况,环境等。此外,它还提供了Spring Boot应用程序上的端点actuator/refresh ,以刷新bean配置。

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

Make the above changes and you are ready to refresh the microservice configuration at runtime. You can update the configuration in config_repo and call the http://$microservice-host/actuator/refresh to refresh the configuration of our Product Catalog Service.

进行以上更改,您就可以在运行时刷新微服务配置。 您可以在config_repo更新配置,然后调用http://$microservice-host/actuator/refresh刷新我们的产品目录服务的配置。

Please note that the request type for /refresh endpoint is POST

请注意,/ refresh端点的请求类型为POST

This feature did help in refreshing the service at runtime but we still need to call the refresh endpoint. If you want you can make the whole process automated based on event-driven communications. This is a wider topic though and will be covered separately.

此功能确实有助于在运行时刷新服务,但我们仍然需要调用刷新端点。 如果您愿意,可以基于事件驱动的通信使整个过程自动化。 但是,这是一个更广泛的主题,将单独讨论。

下一步 (Next Steps)

In this exercise, we implemented a sample Configuration Service. The complete code of this exercise can be referred here at Github.

在本练习中,我们实现了一个示例配置服务。 此练习的完整代码可以在Github上找到。

For advanced topics like configuration security, integration with non-git sources, event-driven updates can be found at https://cloud.spring.io/spring-cloud-config/reference/html/.

对于高级主题,例如配置安全性,与非git源的集成,可以在https://cloud.spring.io/spring-cloud-config/reference/html/中找到事件驱动的更新。

In the next section, we will be developing another microservices pattern — Service Discovery.

在下一节中,我们将开发另一个微服务模式-Service Discovery

翻译自: https://medium.com/an-idea/spring-boot-microservices-developing-config-as-a-service-fa4866085086

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值