管理配置

管理配置的四个原则

  • 隔离
    将服务配置信息与服务的实例物理部署完全分离
  • 抽象
    抽象服务接口背后的配置数据访问
  • 集中
    将应用程序配置集中到尽可能少的存储库中
  • 稳定
    实现高可用和冗余

建立Spring Cloud 配置服务器

Spring Cloud配置服务器是构建在Spring Boot之上基于REST的应用程序。

添加一个新的项目,称为confsvr。

添加如下依赖:

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

我们会使用license服务作为使用Spring Cloud 配置服务的客户端。为了简单,我们将使用三个环境来设置应用的配置数据:default,用于本地运行;dev以及prod。

在每个环境中,将会设置两个配置属性

  • 由license服务直接使用的示例属性
  • 存储license服务数据的Postgres数据的配置属性
  1. 增加​​@EnableConfigServer​​注解
@SpringBootApplication
@EnableConfigServer
public class ConfsvrApplication {

public static void main(String[] args) {
SpringApplication.run(ConfsvrApplication.class, args);
}
}
  1. 添加bootstrap.yml文件
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://gitee.com/safika/eagle-eye-config.git
# 查询配置文件的位置,可通过,分隔
search-paths: licensea

启动,访问http://localhost:8888/license/dev,可以看到输出如下:

{
name: "license",
profiles: [
"dev"
],
label: null,
version: "13fc97719dca692cc0fe793eb62bedfca42766da",
state: null,
propertySources: [{
name: "https://gitee.com/safika/eagle-eye-config.git/license/license-dev.yml",
source: {
tracer.property: "I AM THE DEFAULT",
spring.jpa.show - sql: true,
management.security.enabled: false,
endpoints.health.sensitive: false
}
}]
}

新建配置服务客户端

  1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

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

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

我们使用h2嵌入式数据库用于开发测试,因为Spring boot能帮我自动配置默认属性,因此不需要我们自己写默认数据库名称,驱动,用户名,密码等。

  1. 指定配置文件
spring:
application:
# 和配置服务器指定的目录相同
name: license
profiles:
active: dev
cloud:
config:
uri: http://localhost:8888 #

关键步骤已经完成了,接下来是一些其他类的编写

package com.learn.license.config;

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

@Component
public class ServiceConfig{

// 通过@Value注解注入配置文件中的属性
@Value("${tracer.property}")
private String exampleProperty;

public String getExampleProperty(){
return exampleProperty;
}
}

package com.learn.license.controllers;

import com.learn.license.model.License;
import com.learn.license.services.LicenseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
* @RequestMapping 暴露Controller的根URL
* {organizationId}是一个占位符,表示URL在每次调用会传递一个organizationId参数
*/
@RestController
@RequestMapping(value = "/v1/organizations/{organizationId}/licenses")
public class LicenseServiceController {

@Autowired
private LicenseService licenseService;


@RequestMapping(value="/",method = RequestMethod.GET)
public List<License> getLicenses(@PathVariable("organizationId") String organizationId) {
return licenseService.getLicensesByOrg(organizationId);
}

@RequestMapping(value="/{licenseId}",method = RequestMethod.GET)
public License getLicenses( @PathVariable("organizationId") String organizationId,
@PathVariable("licenseId") String licenseId) {

return licenseService.getLicense(organizationId,licenseId);
}

@RequestMapping(value="{licenseId}",method = RequestMethod.PUT)
public String updateLicenses( @PathVariable("licenseId") String licenseId) {
return String.format("This is the put");
}

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

@RequestMapping(value="{licenseId}",method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
public String deleteLicenses( @PathVariable("licenseId") String licenseId) {
return String.format("This is the Delete");
}
}


package com.learn.license.model;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
@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 License withComment(String comment){
this.setComment(comment);
return this;
}

}

package com.learn.license.repository;

import com.learn.license.model.License;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

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


package com.learn.license.services;

import com.learn.license.config.ServiceConfig;
import com.learn.license.model.License;
import com.learn.license.repository.LicenseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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);
return license.withComment(config.getExampleProperty());
}

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

public void saveLicense(License license){
license.setLicenseId( UUID.randomUUID().toString());
licenseRepository.save(license);
}

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

public void deleteLicense(License license){
licenseRepository.delete( license.getLicenseId());
}

}

以及data.sql(放到src/resource目录下,一般用于初始化数据)

DELETE FROM licenses;



INSERT INTO licenses (license_id, organization_id, license_type, product_name, license_max, license_allocated)
VALUES ('f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a', '1', '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', '1', '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', '2', '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', '2', 'core-prod','WildCat Application Gateway', 16,16);

启动,访问http://localhost:8080/v1/organizations/1/licenses/f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a

得到输出如下

{
"licenseId": "f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a",
"organizationId": "1",
"productName": "customer-crm-co",
"licenseType": "user",
"licenseMax": 100,
"licenseAllocated": 5,
"comment": "I AM THE DEFAULT"
}

完成项目地址: ​​https://gitee.com/safika/eagle-eye​