《Spring微服務實戰》讀書筆記——通過配置伺服器來管理配置
阿新 • • 發佈:2018-12-08
管理配置
管理配置的四個原則
- 隔離
將服務配置資訊與服務的例項物理部署完全分離 - 抽象
抽象服務介面背後的配置資料訪問 - 集中
將應用程式配置集中到儘可能少的儲存庫中 - 穩定
實現高可用和冗餘
建立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資料的配置屬性
- 增加
@EnableConfigServer
註解
@SpringBootApplication
@EnableConfigServer
public class ConfsvrApplication {
public static void main(String[] args) {
SpringApplication.run(ConfsvrApplication.class, args);
}
}
- 新增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
}
}]
}
新建配置服務客戶端
- 新增依賴
<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能幫我自動配置預設屬性,因此不需要我們自己寫預設資料庫名稱,驅動,使用者名稱,密碼等。
- 指定配置檔案
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"
}