Spring Cloud Config 分布式配置

Spring Cloud Config为分布式系统中的外部化配置提供服务器和客户端支持。使用Config Server,您可以集中管理所有环境中应用程序的外部属性。 当应用程序从开发人员到测试人员进入生产过程进入生产过程时,您可以管理这些环境之间的配置,并确保应用程序具有它们迁移时所需的一切。

1 快速开始

用于构建分布式配置的开源项目如下所示:

项目名称

描述

特点

Etcd

使用Go开发的开源项目,用于服务发现和键值管理,使用raft协议作为它的分布式计算模型

非常快和可伸缩 

可分布式 

命令行驱动 

易于搭建和使用

Eureka

由Netflix开发。久经测试,用于服务发现和键值管理

分布式键值存储 

灵活,需要费些功夫去设置 

提供开箱即用的动态客户端刷新

项目名称

描述

特点

Consul

由Hashicorp开发,特性上类似于Etcd和Eureka,它的分布式计算模型使用了不同的算法(SWIM协议)

快速 

提供本地服务发现功能,可直接与DNS集成 

没有提供开箱即用的动态客户端刷新

ZooKeeper

一个提供分布式锁定功能的Apache项目,经常用作访问键值数据的配置管理解决方案

最古老的、最久经测试的解决方案

使用最为复杂 

可用作配置管理,

但只有在其他架构中已经使用了ZooKeeper的时候才考虑使用它

项目名称

描述

特点

Spring Cloud

server

一个开源项目,提供不同后端支持的通用配置管理解决方案。它可以将Git、Eureka和Consul作为后端进行整合

非分布式键值存储 

提供了对Spring和非Spring服务的紧密集成 

可以使用多个后端来存储配置数据,

包括共享文件系统、Eureka、Consul和Git

推荐使用Spring Cloud配置服务器。原因包括以下几个:

  1. Spring Cloud配置服务器易于搭建和使用。
  2. Spring Cloud配置与Spring Boot紧密集成。
  3. Spring Cloud配置服务器提供多个后端用于存储配置数据。如果读者已经使用了Eureka和Consul等工具,那么可以将它们直接插入Spring Cloud配置服务器中。
  4. Spring Cloud配置服务器可以直接与Git源控制平台集成。Spring Cloud配置与Git的集成消除了解决方案的额外依赖,并使版本化应用程序配置数据成为可能。

Postman

Postman是用于API开发的协作平台。Postman的功能简化了构建API的每个步骤并简化了协作,因此您可以更快地创建更好的API。

MySQL数据库

MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理。

创建一个MySQL数据库eagle_eye_local

创建licenses许可证表

DROP TABLE IF EXISTS licenses;

CREATE TABLE licenses (
  license_id        VARCHAR(100) PRIMARY KEY NOT NULL,
  organization_id   TEXT NOT NULL,
  license_type      TEXT NOT NULL,
  product_name      TEXT NOT NULL,
  license_max       INT   NOT NULL,
  license_allocated INT,
  comment           VARCHAR(100));


INSERT INTO licenses (license_id,  organization_id, license_type, product_name, license_max, license_allocated)
VALUES ('f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a', 'e254f8c-c442-4ebe-a82a-e2fc1d1ff78a', 'user','customer-crm-co', 100,5);
INSERT INTO licenses (license_id,  organization_id, license_type, product_name, license_max, license_allocated)
VALUES ('t9876f8c-c338-4abc-zf6a-ttt1', 'e254f8c-c442-4ebe-a82a-e2fc1d1ff78a', 'user','suitability-plus', 200,189);
INSERT INTO licenses (license_id,  organization_id, license_type, product_name, license_max, license_allocated)
VALUES ('38777179-7094-4200-9d61-edb101c6ea84', '442adb6e-fa58-47f3-9ca2-ed1fecdfe86c', 'user','HR-PowerSuite', 100,4);
INSERT INTO licenses (license_id,  organization_id, license_type, product_name, license_max, license_allocated)
VALUES ('08dbe05-606e-4dad-9d33-90ef10e334f9', '442adb6e-fa58-47f3-9ca2-ed1fecdfe86c', 'core-prod','WildCat Application Gateway', 16,16);

2 Spring Cloud Config 服务器

Spring Cloud Config Server为外部配置提供了一个基于HTTP资源的API。

创建一个Spring Boot微服务作为Spring Cloud Config 服务端。

在pom.xml中增加以下依赖jar包:

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-server</artifactId>
		</dependency>

像所有Spring Boot应用程序一样,它默认在端口8080上运行,但是您可以通过各种方式将其切换到更传统的端口8888。如以下示例所示:

server:
  port: 8888
spring:
  application:
    name: configserver
  profiles:
    active: native
  cloud:
    config:
      server:
        native:
          search-locations: classpath:config/,classpath:config/licensingservice

应用程序配置文件的命名约定是“应用程序名称-环境名称.yml”。 环境名称直接转换为可以浏览配置信息的 URL。随后,启动许可证微服务示例时,要运行哪个服务环境是由在命令行服务启动时传入的 Spring Boot 的 profile 指定的。如果在命令行上没有传入profile,Spring Boot将始终默认加载随应用程序打包的application.yml文件中的配置数据。

config/licensingservice/licensingservice.yml

example.property: "I AM IN THE DEFAULT"
spring.jpa.database: "MYSQL"
spring.jpa.show-sql: "true"
spring.datasource.platform:  "mysql"
spring.database.driver-class-name: "com.mysql.cj.jdbc.Driver"
spring.datasource.url: "jdbc:mysql://localhost:3306/eagle_eye_local?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"
spring.datasource.username: "root"
spring.datasource.password: "{cipher}dcd4e3e74b79da1ae5c8b383e1c40d1c4793b51e275c0ed3d9331ac64da2053b"
spring.datasource.testWhileIdle: "true"
spring.datasource.validationQuery: "SELECT 1"
spring.jpa.properties.hibernate.dialect: "org.hibernate.dialect.MySQLDialect"

licensingservice-dev.yml

spring.jpa.database: "MYSQL"
spring.datasource.platform:  "mysql"
spring.jpa.show-sql: "false"
spring.database.driver-class-name: "com.mysql.cj.jdbc.Driver"
spring.datasource.url: "jdbc:mysql://localhost:3306/eagle_eye_dev?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"
spring.datasource.username: "root"
spring.datasource.password: "123456"
spring.datasource.testWhileIdle: "true"
spring.datasource.validationQuery: "SELECT 1"
spring.jpa.properties.hibernate.dialect: "org.hibernate.dialect.MySQLDialect"

licensingservice-test.yml

spring.jpa.database: "MYSQL"
spring.datasource.platform:  "mysql"
spring.jpa.show-sql: "false"
spring.database.driver-class-name: "com.mysql.cj.jdbc.Driver"
spring.datasource.url: "jdbc:mysql://localhost:3306/eagle_eye_test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"
spring.datasource.username: "root"
spring.datasource.password: "123456"
spring.datasource.testWhileIdle: "true"
spring.datasource.validationQuery: "SELECT 1"
spring.jpa.properties.hibernate.dialect: "org.hibernate.dialect.MySQLDialect"

licensingservice-prod.yml

spring.jpa.database: "MYSQL"
spring.datasource.platform:  "mysql"
spring.jpa.show-sql: "false"
spring.database.driver-class-name: "com.mysql.cj.jdbc.Driver"
spring.datasource.url: "jdbc:mysql://localhost:3306/eagle_eye_prod?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"
spring.datasource.username: "root"
spring.datasource.password: "123456"
spring.datasource.testWhileIdle: "true"
spring.datasource.validationQuery: "SELECT 1"
spring.jpa.properties.hibernate.dialect: "org.hibernate.dialect.MySQLDialect"

通过使用@EnableConfigServer注释,服务器可嵌入到Spring Boot应用程序中。因此,以下应用程序是配置服务器:

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
  public static void main(String[] args) {
    SpringApplication.run(ConfigServerApplication.class, args);
  }
}

启动服务,访问http://localhost:8888/licensingservice/default,查询配置信息,如下图所示:

3 Spring Cloud Config 客户端

创建一个Spring Boot微服务作为Spring Cloud Config 客户端。

在pom.xml中增加以下依赖jar包:

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-client</artifactId>
		</dependency>

application.yml

spring:
  application:
    name: licensingservice
  profiles:
    active:
      default
  cloud:
    config:
      uri: http://localhost:8888

LicensingServiceApplication.java

@SpringBootApplication
public class LicensingServiceApplication {

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

}

ServiceConfig.java

package com.example.licenses.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class ServiceConfig{

  @Value("${example.property}")
  private String exampleProperty;

  public String getExampleProperty(){
    return exampleProperty;
  }
}

License.java

package com.example.licenses.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "licenses")
public class License {
	@Id
	@Column(name = "license_id", nullable = false)
	private String licenseId;

	@Column(name = "organization_id", nullable = false)
	private String organizationId;

	@Column(name = "product_name", nullable = false)
	private String productName;

	@Column(name = "license_type", nullable = false)
	private String licenseType;

	@Column(name = "license_max", nullable = false)
	private Integer licenseMax;

	@Column(name = "license_allocated", nullable = false)
	private Integer licenseAllocated;

	@Column(name = "comment")
	private String comment;

	public Integer getLicenseMax() {
		return licenseMax;
	}

	public void setLicenseMax(Integer licenseMax) {
		this.licenseMax = licenseMax;
	}

	public Integer getLicenseAllocated() {
		return licenseAllocated;
	}

	public void setLicenseAllocated(Integer licenseAllocated) {
		this.licenseAllocated = licenseAllocated;
	}

	public String getLicenseId() {
		return licenseId;
	}

	public void setLicenseId(String licenseId) {
		this.licenseId = licenseId;
	}

	public String getOrganizationId() {
		return organizationId;
	}

	public void setOrganizationId(String organizationId) {
		this.organizationId = organizationId;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getLicenseType() {
		return licenseType;
	}

	public void setLicenseType(String licenseType) {
		this.licenseType = licenseType;
	}

	public String getComment() {
		return comment;
	}

	public void setComment(String comment) {
		this.comment = comment;
	}

	public License withId(String id) {
		this.setLicenseId(id);
		return this;
	}

	public License withOrganizationId(String organizationId) {
		this.setOrganizationId(organizationId);
		return this;
	}

	public License withProductName(String productName) {
		this.setProductName(productName);
		return this;
	}

	public License withLicenseType(String licenseType) {
		this.setLicenseType(licenseType);
		return this;
	}

	public License withLicenseMax(Integer licenseMax) {
		this.setLicenseMax(licenseMax);
		return this;
	}

	public License withLicenseAllocated(Integer licenseAllocated) {
		this.setLicenseAllocated(licenseAllocated);
		return this;
	}

	public License withComment(String comment) {
		this.setComment(comment);
		return this;
	}

}

LicenseRepository.java

package com.example.licenses.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.example.licenses.model.License;

import java.util.List;

@Repository
public interface LicenseRepository extends CrudRepository<License, String> {
	
	public List<License> findByOrganizationId(String organizationId);

	public License findByOrganizationIdAndLicenseId(String organizationId, String licenseId);
}

LicenseService.java

package com.example.licenses.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.licenses.config.ServiceConfig;
import com.example.licenses.model.License;
import com.example.licenses.repository.LicenseRepository;

import java.util.List;
import java.util.UUID;

@Service
public class LicenseService {

	@Autowired
	private LicenseRepository licenseRepository;

	@Autowired
	ServiceConfig config;

	public License getLicense(String organizationId, String licenseId) {
		License license = licenseRepository.findByOrganizationIdAndLicenseId(organizationId, licenseId);
		if (license != null) {
			license.withComment(config.getExampleProperty());
		}
		return license;
	}

	public List<License> getLicensesByOrg(String organizationId) {
		return licenseRepository.findByOrganizationId(organizationId);
	}

	public void saveLicense(License license) {
		license.withId(UUID.randomUUID().toString());

		licenseRepository.save(license);

	}

	public void updateLicense(License license) {
		licenseRepository.save(license);
	}

	public void deleteLicense(String licenseId) {
		licenseRepository.deleteById(licenseId);
	}

}

LicenseServiceController.java

package com.example.licenses.controllers;

import com.example.licenses.model.License;
import com.example.licenses.services.LicenseService;
import com.example.licenses.config.ServiceConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;

@RestController
@RequestMapping(value = "organizations/{organizationId}/licenses")
public class LicenseServiceController {
	@Autowired
	private LicenseService licenseService;

	@Autowired
	private ServiceConfig serviceConfig;

	/**
	 * 查询所有对象
	 * 
	 * @param organizationId
	 * @return
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public List<License> getLicenses(@PathVariable("organizationId") String organizationId) {

		return licenseService.getLicensesByOrg(organizationId);
	}

	/**
	 * 查询单个对象
	 * 
	 * @param organizationId
	 * @param licenseId
	 * @return
	 */
	@RequestMapping(value = "/{licenseId}", method = RequestMethod.GET)
	public License getLicenses(@PathVariable("organizationId") String organizationId,
			@PathVariable("licenseId") String licenseId) {

		return licenseService.getLicense(organizationId, licenseId);
	}

	/**
	 * 新增对象
	 * 
	 * @param license
	 */
	@RequestMapping(value = "/", method = RequestMethod.POST)
	public void saveLicenses(@RequestBody License license) {
		licenseService.saveLicense(license);
	}

	/**
	 * 更新对象
	 * 
	 * @param licenseId
	 * @return
	 */
	@RequestMapping(value = "/", method = RequestMethod.PUT)
	public String updateLicenses(@RequestBody License license) {
		licenseService.updateLicense(license);
		return String.format("This is the put");
	}

	/**
	 * 删除对象
	 * 
	 * @param licenseId
	 * @return
	 */
	@RequestMapping(value = "{licenseId}", method = RequestMethod.DELETE)
	// @ResponseStatus(HttpStatus.NO_CONTENT)
	public String deleteLicenses(@PathVariable("licenseId") String licenseId) {
		licenseService.deleteLicense(licenseId);
		return String.format("This is the Delete");
	}
}

启动服务,访问http://localhost:8080/organizations/e254f8c-c442-4ebe-a82a-e2fc1d1ff78a/licenses/f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a,查询许可证信息,如下图所示:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章