如何使用Spring Cloud Consul发现Spring Cloud服务

611 阅读5分钟

使用Spring Cloud Consul的Spring Cloud服务发现

Spring Boot consul是一个用于Spring Boot应用程序的服务发现和配置框架。它是一个轻量级的、可扩展的、易于使用的服务发现和配置框架,采用Spring Boot和Spring Cloud设计。

本教程将创建一个在线应用程序来管理商店。我们将使用微服务架构开发该应用。

我们将有两个服务。

  1. 产品服务--它将管理系统中所有商店销售的所有产品。
  2. 商店服务=管理系统中商店的相关信息。

前提条件

  1. 在你的机器上安装ConsulJDK
  2. Spring框架和Spring Boot方面的知识。

设置consul

在本教程中,我们需要在我们的开发机上安装consul。

导航到consul网站,为你的操作系统下载最新版本的consul。然后,解压下载的文件,运行consul命令来启动consul代理,如下图所示。

consul agent -server -bootstrap-expect=1 -data-dir=consul-data -ui -bind=<your ip address>

注意:用你的ip地址代替。

上述命令的输出应该如下。

test@DEV-34:/$ sudo /usr/local/bin/consul agent -server -bootstrap-expect=1 -data-dir=consul-data -ui -bind=192.168.1.169
==> Starting Consul agent...
           Version: '1.8.4'
           Node ID: '2bff16b4-eaf1-540d-1e96-bb168f5fdf74'
         Node name: 'DEV-34'
        Datacenter: 'dc1' (Segment: '<all>')
            Server: true (Bootstrap: true)
       Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: -1, DNS: 8600)
      Cluster Addr: 192.168.1.169 (LAN: 8301, WAN: 8302)
           Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false

==> Log data will now stream in as it occurs:

    2022-02-09T13:30:32.813+0300 [WARN]  agent: BootstrapExpect is set to 1; this is the same as Bootstrap mode.

现在我们已经在我们的开发机器上安装并运行了consul,我们需要通过在我们的网络浏览器上导航到http://localhost:8500,来验证consul代理是否完全正常。我们可以从浏览器的仪表板上看到我们的开发机器上运行的服务,如下图所示。

Consul dashboard

设置Spring Boot应用程序

产品服务

在你的网络浏览器上导航到spring initilzr。输入应用程序名称为product-service ,包名称为com.example.productservice

添加Actuator,Lombok,Web,Rest repositoriesConsul discoveries 作为项目依赖。

点击生成按钮,下载具有所需依赖性配置的模板项目代码。

解压缩下载的压缩文件,并在你喜欢的IDE中打开。导航到src/main/java/com/example/productservice/ 目录并更新ProductServiceApplication.java 文件,如下所示。

@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {

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

}

@EnableDiscoveryClient 是用来启用服务发现和配置框架的。这个注解允许服务向consul代理注册自己。

application.properties 文件中,添加以下配置。

server.port=9090
spring.application.name:product-service
management.security.enabled=false
  • server.port:服务的端口号。应用程序将在这个端口上启动和运行。
  • spring.application.name:服务的名称。这个名字用于在consul中注册该服务。其他服务也可以通过这个名字发现这个服务。
  • management.security.enabled:禁用执行器所暴露的管理端点的安全性。

在根项目包中,创建一个名为Product 的新的Java类,并用如下所示的代码片断对其进行更新。

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
@ToString
public class Product {
    String name;
    float price;
}
  • @AllArgsConstructor:该注解用于创建一个具有所有字段的构造函数。
  • @NoArgsConstructor:该注解用于创建一个没有任何字段的构造函数。
  • @Setter:该注解用于为所有字段创建设置器。
  • @Getter:该注解用于为所有字段创建获取器。
  • @ToString:该注解用于为该类创建一个toString方法。

为了向世界展示我们的服务,我们需要创建一个新的Java类,名为ProductController ,它将接受HTTP请求。用下面的代码片段更新它。

@RestController
public class ProductController {
    private static final Map<String, List<Product>> productDatabase;

    static {
        productDatabase = new HashMap<>();
        List<Product> products = new ArrayList<>();
        Product sugar = new Product("Sugar", 120.0f);
        products.add(sugar);
        Product salt = new Product("Salt", 30.0f);
        products.add(salt);

        productDatabase.put("ABC shop", products);

        List<Product> items = new ArrayList<>();
        Product soap = new Product("Soap", 30.0f);
        items.add(soap);
        Product cooking = new Product("Cooking", 70.0f);
        items.add(cooking);

        productDatabase.put("XYZ", items);
    }

    @RequestMapping(value = "/shopproducts/{shopName}", method = RequestMethod.GET)
    public List<Product> getProductPerShop(@PathVariable("shopName") String shopName) {
        List<Product> products = productDatabase.get(shopName);
        if (products == null) {
            products = new ArrayList<>();
            Product product = new Product("No product", 0f);
            products.add(product);
        }
        return products;
    }
}
  • @RestController:这个注解是用来创建一个控制器类。
  • 由于我们没有实现数据库层,我们在静态块中声明了一个产品的静态地图。这将充当我们的数据库层。
  • getProductPerShop:这个方法用来获取一个给定商店的产品。它根据商店名称过滤产品并返回产品列表。

商店服务

在你的网络浏览器上导航到spring initilzr。输入应用程序名称为shop-service ,包名称为com.example.productservice

添加Actuator,Lombok,Web,Rest repositoriesConsul discoveries 作为项目依赖。

点击生成按钮,下载具有所需依赖性配置的模板项目代码。

解压缩下载的压缩文件,并在你最喜欢的IDE中打开。导航到src/main/java/com/example/shopservice/ 目录并更新ShopServiceApplication.java 文件,如下所示。

@SpringBootApplication
@EnableDiscoveryClient
public class ShopServiceApplication {

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

}

@EnableDiscoveryClient 是用来启用服务发现和配置框架的。这个注解允许服务向consul代理注册自己。

在根应用程序目录中,创建一个新的Java类,命名为ShopServiceDelegate ,并用下面的代码片断更新它。

@Service
public class ShopServiceDelegate {
    @Autowired
    RestTemplate template;

    public String getDataFromProductService(String shopName) {
        String response = template.exchange("http://product-service/shopproducts/{shopName}",
                HttpMethod.GET, null, new ParameterizedTypeReference<String>() {
                }, shopName).getBody();

        System.out.println("Received " + response + " -  " + new Date());

        return "Shop Name -  " + shopName + " :::  Product details " + response + " -  " + new Date();

    }

    @Bean
    @LoadBalanced
    public RestTemplate template() {
        return new RestTemplate();
    }
}
  • @Service:该注解用于创建一个服务类。
  • getDataFromProductService:这个方法用来获取一个给定商店的产品。它根据商店名称过滤产品并返回产品列表。
  • template():这个方法用于创建一个RestTemplate Bean。我们已经将这个Bean标记为@LoadBalanced ,以创建一个负载平衡的RestTemplate。当这个服务的许多实例被运行时,一个负载平衡的RestTemplate将被创建。

为了使其他服务能够与商店服务进行通信,我们需要创建一个名为ShopServiceRestController 的新Java类,它将接受HTTP请求。用下面的代码片段更新它。

@RestController
@AllArgsConstructor
public class ShopServiceController {
    ShopServiceDelegate shopServiceDelegate;

    @RequestMapping(value = "/getshopdetails/{shopName}", method = RequestMethod.GET)
    public String getProducts(@PathVariable("shopName") String shopName) {
        return shopServiceDelegate.getDataFromProductService(shopName);
    }
}
  • @RestController:该注解用于创建一个控制器类。
  • @AllArgsConstructor:该注解用于创建一个包含所有字段的构造函数。通过这个注解,我们通过构造函数注入ShopServiceDelegate Bean。

测试

运行产品服务,并验证它正在运行,并且可以被Consul仪表盘中的consul代理发现,如下图所示。

Product Service

现在,产品服务已经成功运行,我们可以运行商店服务。一旦商店服务启动,我们可以从consul仪表板上验证它的运行没有问题,并且可以被consul代理发现,如下图所示。

Shop service

当我们向http://localhost:8098/getshopdetails/ABC 发出GET请求时我们会得到一个如下的响应。

[{"name":"Soap","price":30.0},{"name":"Cooking","price":70.0}] -  Thu Feb 10 09:15:17 EAT 2022

我们可以向产品服务请求商店服务,而不需要产品服务的URL和端口。我们只能得到带有服务名称和端点的响应。Consul简化了服务发现。

当与Docker一起使用时,我们不需要跟踪IP地址的变化,但服务可以用服务名称进行通信。

总结

在本教程中,我们已经学会了如何在我们的开发机器上有效地部署Consul服务注册表和发现服务器及客户端。

现在你可以尝试使用微服务架构实现一个Spring Boot项目,并使用Spring Cloud consul进行部署。