zoukankan      html  css  js  c++  java
  • 3.3 将Spring Cloud Config与Spring Boot客户端集成

     
      在上一章中,我们构建了一个简单的许可证服务框架,这个框架只是返回一个代表数据库中单个许可记录的硬编码Java对象。在下一个示例中,我们将构建许可证服务,并与持有许可数据的Postgres数据库进行交流。
        我们将使用Spring Data与数据库进行通信,并将数据从许可证表映射到保存数据的POJO。数据库连接和一条简单的属性将从Spring Cloud配置服务器中读出。图3-6展示了许可证服务和Spring Cloud配置服务之间的交互。
     
    图3-6 使用开发环境profile检索配置信息
     
    当许可证服务首次启动时,将通过命令行传递两条信息:Spring的profile和许可证服务用于与Spring Cloud配置服务通信的端点。Spring的profile值映射到为Spring服务检索属性的环境。当许可证服务首次启动时,它将通过从Spring的profile传入构建的端点与Spring Cloud Config服务进行联系。然后,Spring Cloud Config服务将会根据URI上传递过来的特定Spring profile,使用已配置的后端配置存储库(文件系统、Git、Consul或Eureka)来检索相应的配置信息,然后将适当的属性值传回许可证服务。接着,Spring Boot框架将这些值注入应用程序的相应部分。
        3.3.1 建立许可证服务对Spring Cloud Config服务器的依赖
        让我们把焦点从配置服务器转移到许可证服务。我们需要做的第一件事,就是在许可证服务中为Maven文件添加更多的条目。代码清单3-4展示了需要添加的条目。
     
    代码清单3-4 许可证服务所需的其他Maven依赖项
    <dependency>   
    <groupId>org.springframework.boot</groupId>   
    <artifactId>spring-boot-starter-data-jpa</artifactId>    ⇽---  告诉Spring Boot将要在服务中使用Java Persistence API(JPA) </dependency> 
    <dependency>   
    <groupId>postgresql</groupId>   
    <artifactId>postgresql</artifactId>    ⇽---  告诉Spring Boot拉取Postgres JDBC驱动程序   
    <version>9.1-901.jdbc4</version> 
    </dependency> 
    <dependency>   
    <groupId>org.springframework.cloud</groupId>   
    <artifactId>spring-cloud-config-client</artifactId>    ⇽---  告诉Spring Boot拉取Spring Cloud Config客户端所需的所有依赖项 </dependency>
        第一个和第二个依赖项spring-boot-starter-data-jpa和postgresql导入了Spring Data Java Persistence API(JPA)和Postgres JDBC驱动程序。最后一个依赖项是spring-cloud-config-client,它包含与Spring Cloud配置服务器交互所需的所有类。
     
        3.3.2 配置许可证服务以使用Spring Cloud Config
        在定义了Maven依赖项后,需要告知许可证服务在哪里与Spring Cloud配置服务器进行联系。在使用Spring Cloud Config的Spring Boot服务中,配置信息可以在bootstrap.yml和application.yml这两个配置文件之一中设置。
        在其他所有配置信息被使用之前,bootstrap.yml文件要先读取应用程序属性。一般来说,bootstrap.yml文件包含服务的应用程序名称、应用程序profile和连接到Spring Cloud Config服务器的URI。希望保留在本地服务(而不是存储在Spring Cloud Config中)的其他配置信息,都可以在服务中的application.yml文件中进行本地设置。通常情况下,即使Spring Cloud Config服务不可用,我们也会希望存储在application.yml 文件中的配置数据可用。bootstrap.yml 和application.yml保存在项目的src/main/resources文件夹中。
        要使许可证服务与Spring Cloud Config服务进行通信,需要添加一个licensing-service/src/ main/resources/bootstrap.yml文件,并设置3个属性,即spring.application.name、spring. profiles.active和spring.cloud.config.uri。
        代码清单3-5展示了许可证服务的bootstrap.yml文件。
     
        代码清单3-5 配置许可证服务的bootstrap.yml文件
        spring:   
            application:     
                name: licensingservice    ⇽---  指定许可证服务的名称,以便Spring Cloud Config客户端知道正在查找哪个服务   
             profiles:     
                active:       
                    default    ⇽---  指定服务应该运行的默认profile。profile映射到环境   
            cloud:   
                config:         
                    uri: http://localhost:8888    ⇽---  指定Spring Cloud Config服务器的位置
        注意
        
        Spring Boot应用程序支持两种定义属性的机制:YAML(Yet another Markup Language)和使用“.”分隔的属性名称。我们选择YAML作为配置应用程序的方法。YAML属性值的分层格式直接映射到spring.application.name、spring.profiles.active和spring.cloud.config.uri名称。
     
    spring.application.name是应用程序的名称(如licensingservice)并且必须直接映射到Spring Cloud配置服务器中的目录的名称。对于许可证服务,需要在Spring Cloud配置服务器上有一个名为licensingservice的目录。
        第二个属性spring.profiles.active用于告诉Spring Boot应用程序应该运行哪个profile。profile是区分Spring Boot应用程序要使用哪个配置数据的机制。对于许可证服务的profile,我们将支持服务的环境直接映射到云配置环境中。例如,通过作为profile传入开发环境,Spring Cloud配置服务器将使用开发环境的属性。如果没有设置profile,许可证服务将使用默认profile。
     
    第三个也是最后一个属性spring.cloud.config.uri是许可证服务查找Spring Cloud配置服务器端点的位置。在默认情况下,许可证服务将在http://localhost:8888上查找配置服务器。在本章的后面,读者将看到如何在应用程序启动时覆盖boostrap.yml和application.yml文件中定义的不同属性,这样可以告知许可证微服务应该运行哪个环境。
        现在,如果启动Spring Cloud配置服务,并在本地计算机上运行相应的Postgres数据库,那么就可以使用默认profile启动许可证服务。这可以通过切换到许可证服务的目录并执行以下命令来完成:
     
    mvn spring-boot: run
        通过运行此命令而不设置任何属性,许可证服务器将自动尝试使用端点(http://localhost: 8888)和在许可证服务的bootstrap.yml文件中定义的活跃profile(默认),连接到Spring Cloud配置服务器。
        如果要覆盖这些默认值并指向另一个环境,可以通过将许可证服务项目编译到JAR,然后使用-D系统属性来运行这个JAR来实现。下面的命令行演示了如何使用非默认profile启动许可证服务:
        java  -Dspring.cloud.config.uri=http://localhost:8888        
                -Dspring.profiles.active=dev        
                -jar target/licensing-service-0.0.1-SNAPSHOT.jar 
    使用上述命令行将覆盖两个参数,即spring.cloud.config.uri和spring.profiles. active。
    使用-Dspring.cloud.config.uri=http://localhost:8888系统属性将指向一个本地运行的配置服务器。
        注意
        
        如果读者尝试从自己的台式机上使用上述的Java命令来运行从本章的GitHub存储库下载的许可证服务,将会运行失败,这是因为没有运行桌面Postgres服务器,并且GitHub存储库中的源代码在配置服务器上使用了加密。本章稍后将介绍加密。前面的例子演示了如何通过命令行来覆盖Spring属性。
        使用-Dspring.profiles.active=dev系统属性,可以告诉许可证服务使用开发环境profile(从配置服务器读取),从而连接到开发环境的数据库的实例。
     
        使用环境变量传递启动信息
        在这些示例中,将这些值硬编码传递给-D参数值。在云中所需的大部分应用程序配置数据都将位于配置服务器中。但是,对于启动服务所需的信息(如配置服务器的数据),则需要启动VM实例或Docker容器并传入环境变量。
        本书每章的所有代码示例都可以在Docker容器中完全运行。使用Docker,我们可以通过特定环境的Docker-compose文件来模拟不同的环境,从而协调所有服务的启动。容器所需的特定环境值作为环境变量传递到容器。例如,要在开发环境中启动许可证服务,docker/dev/docker-compose.yml文件要包含以下用于许可证服务的条目:
     
    licensingservice:   
    image: ch3-thoughtmechanix/licensing-service   
    ports:     - "8080:8080"   
    environment:     ⇽---  指定许可证服务容器的环境变量的开始     
    PROFILE: "dev"    ⇽---  PROFILE环境变量被传递给Spring Boot服务命令行,告诉Spring Boot应该运行哪个profile     
    CONFIGSERVER_URI: http://configserver:8888    ⇽---  配置服务的端点     
    CONFIGSERVER_PORT: "8888"    
    DATABASESERVER_PORT: "5432"
        该文件中的环境条目包含两个变量PROFILE的值,这是许可证服务将要运行的Spring Boot profile。
    CONFIGSERVER_URI被传递给许可证服务,该属性定义了Spring Cloud配置服务器实例
    的地址,服务将从该URI读取其配置数据的。
        在由容器运行的启动脚本中,我们将这些环境变量以-D参数传递到启动应用程序的JVM。
    在每个项目中,可以制作一个Docker容器,然后该Docker容器使用启动脚本启动该容器中的软件。
    对于许可证服务,容器中的启动脚本位于licensing-service/src/main/docker/run.sh中。
    在run.sh脚本中,以下条目负责启动许可证服务的JVM:
    echo  "********************************************************" 
    echo  "Starting License Server with   $CONFIGSERVER_URI"; 
    echo  "********************************************************" 
    java     -Dspring.cloud.config.uri=$CONFIGSERVER_URI  
                -Dspring.profiles.active=$PROFILE 
                -jar /usr/local/licensingservice/licensing-service-0.0.1-SNAPSHOT.jar 
    因为我们是通过 Spring Boot Actuator 来增强服务的自我检查能力的,所以可以通过访问http://localhost:8080/env来确认正在运行的环境。/env端点将提供有关服务的配置信息的完整列表,包括服务启动的属性和端点,如图3-7所示。
     
    图3-7 可以通过调用/env端点来检查许可证服务加载的配置
     
    图3-7中要注意的关键是,许可证服务的活跃profile是dev。通过观察返回的JSON,还可以看到被返回的Postgres数据库URI是开发环境URI:jdbc:postgresgl://database: 5432/eagle-ege-dev。
        暴露太多的信息
    围绕如何为服务实现安全性,每个组织都会有自己的规则。许多组织认为,服务不应该广播任何有关自己的信息,也不允许像/env端点这样的东西在服务上存在,因为他们相信(这是理所当然的)这样会为潜在的黑客提供太多的信息。Spring Boot为配置Spring Actuator端点返回的信息提供了丰富的功能,这些知识超出了本书的范围。Craig Walls的优秀著作《Spring Boot实战》详细介绍了这个主题,我强烈建议读者回顾一下企业安全策略并阅读
     
    Walls的书,以便能够提供想通过Spring Actuator公开的正确级别的细节。
        3.3.3 使用Spring Cloud配置服务器连接数据源
        至此我们已将数据库配置信息直接注入微服务中。数据库配置设置完毕后,配置许可证微服务就变成使用标准Spring组件来构建和从Postgres数据库中检索数据的练习。许可证服务已被重构成不同的类,每个类都有各自独立的职责。这些类如表3-2所示。
        表3-2 许可证服务的类及其所在位置
     
    类名
     
    位置
     
    License
     
    licensing-service/src/main/java/com/thoughtmechanix/licenses/model
     
    LicenseRepository
     
    licensing-service/src/main/java/com/thoughtmechanix/licenses/repository
     
    LicenseService
     
    licensing-service/src/main/java/com/thoughtmechanix/licenses/services
     
    License类是模型类,它将持有从许可数据库检索的数据。代码清单3-6展示了License类的代码。
        代码清单3-6 单个许可证记录的JPA模型代码
    package com.thoughtmechanix.licenses.model; 
    import javax.persistence.Column; 
    import javax.persistence.Entity; 
    import javax.persistence.Id; 
    import javax.persistence.Table; 
    @Entity    ⇽---  @Entity注解告诉Spring这是一个JPA类 
    @Table(name = "licenses")    ⇽---  @Table映射到数据库的表 
    public class License{     
    @Id    ⇽---  @Id将该字段标记为主键     
    @Column(name = "license_id", nullable = false)     ⇽---  @Column 将该字段映射到特定数据库表中的列     
    private String licenseId;     
    @Column(name = "organization_id", nullable = false)     
    private String organizationId;     
    @Column(name = "product_name", nullable = false)     
    private String productName;     /*为了简洁,省略了其余的代码*/ }
        这个类使用了多个Java持久性注解(Java Persistence Annotations,JPA),
    帮助Spring Data框架将Postgres数据库中的licenses表中的数据映射到Java对象。
    @Entity注解让Spring知道这个Java POJO将要映射保存数据的对象。
    @Table注解告诉Spring JPA应该映射哪个数据库表。
    @Id注解标识数据库的主键。最后,数据库中的每一列将被映射到由@Column标记的各个属性。
        Spring Data和JPA框架提供访问数据库的基本CRUD方法。如果要构建其他方法,
    可以使用Spring Data存储库接口和基本命名约定来进行构建。Spring将在启动时从Repository接口解析方法的名称,并将它们转换为基于名称的SQL语句,然后在幕后生成一个动态代理类来完成这项工作。
    代码清单3-7展示了许可证服务的存储库。
       
     代码清单3-7 LicenseRepository接口定义查询方法
        package com.thoughtmechanix.licenses.repository; 
    import com.thoughtmechanix.licenses.model.License; 
    import org.springframework.data.repository.CrudRepository; 
    import org.springframework.stereotype.Repository; 
    import java.util.List; 
    @Repository    ⇽---  告诉Spring Boot这是一个JPA存储库类 
    public interface LicenseRepository     extends CrudRepository<License,String>    ⇽---  定义正在扩展Spring CrudRepository 
    {     
    public List<License> findByOrganizationId(String organizationId);     ⇽---  每个查询方法被Spring解析为SELECT...FROM查询     
    public License findByOrganizationId(String organizationId,String licenseId); 
    }
    存储库接口LicenseRepository用@Repository注解标记,这个注解告诉Spring应该将这个接口视为存储库并为它生成动态代理。
    Spring提供不同类型的数据访问存储库。我们选择使用Spring CrudRepository基类来扩展LicenseRepository类。
    CrudRepository基类包含基本的CRUD方法。除了从CrudRepository扩展的CRUD方法外,
    我们还添加了两个用于从许可表中检索数据的自定义查询方法。
    Spring Data框架将拆开这些方法的名称以构建访问底层数据的查询。
     
    注意
        
    Spring Data框架提供各种数据库平台上的抽象层,并不仅限于关系数据库。该框架还支持NoSQL数据库,如MongoDB和Cassandra。
    与第2章中的许可证服务不同,我们现在已将许可证服务的业务逻辑和数据访问逻辑从LicenseController中分离出来,
    并划分在名为LicenseService的独立服务类中(如代码清单3-8所示)。
        
    代码清单3-8 用于执行数据库命令的LicenseService类
     
    package com.thoughtmechanix.licenses.services; 
    import com.thoughtmechanix.licenses.config.ServiceConfig; 
    import com.thoughtmechanix.licenses.model.License; 
    import com.thoughtmechanix.licenses.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.withId( UUID.randomUUID().toString());         
    licenseRepository.save(license);     
    }        /*为了简洁,省略了其余的代码*/ 
    }
    使用标准的Spring @Autowired注解将控制器、服务和存储库类连接到一起。
     
     
     
     
  • 相关阅读:
    我来悟微服务(1)-夜观天象
    静夜思-十年总结与展望
    【Orleans开胃菜系列2】连接Connect源码简易分析
    【Orleans开胃菜系列1】不要被表象迷惑
    .Net单元测试业务实践
    未能使用“Csc”任务的输入参数初始化该任务
    面试发散思维
    Linux部署DotNetCore记录
    一步一步来熟悉Akka.Net(一)
    午夜杂谈
  • 原文地址:https://www.cnblogs.com/mongotea/p/11973208.html
Copyright © 2011-2022 走看看