SpringCloud所谓的服务注册与发现,流程大致是:
将Springboot微服务客户端项目的地址等信息,通过网络发送到注册中心,由注册中心保存下来。
另一个客户端B访问已经注册到注册中心的服务A,通过注册中心提供的域名解析方式,解析出服务A的地址等信息。
如果提供服务A的客户端有多个,就按照某个策略(比如轮询、负载均衡等)选取一个地址返回。
客户端B访问注册中心返回的地址,获取结果,这里注意,是B直接访问A,而不是注册中心转发,因此要保证B和A是互通的。
目前服务发现的解决方案有Eureka,Consul,Zookeeper等,这三个是SpringCloud官方支持的。
前几篇已经讲了如何搭建Eureka的服务注册发现,上篇介绍了Consul的服务注册。本篇讲下Consul的服务发现,使用两种方式进行服务发现。
代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springcloud.html中的ConsulClient和ConsulFeign组件中查看,并下载。
首发地址:
品茗IT-同步发布
品茗IT提供在线支持:
一键快速构建Spring项目工具
一键快速构建SpringBoot项目工具
一键快速构建SpringCloud项目工具
一站式Springboot项目生成
Mysql一键生成Mybatis注解Mapper
Mysql一键生成SpringDataRest项目
如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。
需要引入spring-boot-starter-web和spring-cloud-starter-consul-discovery,因为要进行服务调用,所以要引入spring-cloud-starter-netflix-ribbon,如果要使用openfeign来进行服务调用,则可以引入spring-cloud-starter-openfeign。
依赖如下:
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>cn.pomitgroupId>
<artifactId>springcloudworkartifactId>
<version>0.0.1-SNAPSHOTversion>
parent>
<artifactId>ConsulClientartifactId>
<name>ConsulClientname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<maven-jar-plugin.version>2.6maven-jar-plugin.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
dependencies>
project>
父模块pom文件可以在https://www.pomit.cn/spring/SpringCloudWork/pom.xml获取。
这里使用yaml文件写配置,application.yml:
server:
port: 8812
spring:
application:
name: consulClient
cloud:
consul:
host: 127.0.0.1
port: 8500
discovery:
prefer-ip-address: true
healthCheckPath: /consul/health
这里面,包含了端口、应用名、consul注册中心信息、注册方式、健康检查路径。
spring.application.name是标识了应用名,注册到consul之后,显示的就是它。
spring.cloud.consul.discovery.prefer-ip-address是使用ip地址,如果不写它,默认是域名,那样测试起来很麻烦。
spring.cloud.consul.discovery.healthCheckPath这个,consul做健康检查的路径。
spring.cloud.consul.port consul的端口。8500 端口基于 HTTP 协议,用于 API 接口或 WEB UI 访问。
上一篇已经注册了一个服务:consulServer。这一篇我们可以注册两个consulClient和consulFeign,来访问consulServer的服务。
使用@EnableDiscoveryClient注解启动类, @EnableDiscoveryClient是将项目作为客户端注册到注册中心的注解,开启服务发现功能。
如果是使用Feign,需要加上@EnableFeignClients注解,开启Feign的使用
ConsulClientApplication :
package cn.pomit.springbootwork.consulclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
//@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ConsulClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulClientApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
这里的RestTemplate使用@LoadBalanced注解,我们跟踪RestTemplate的时候可以看到,RestTemplate多了个LoadBalancerInterceptor。
不管是服务注册还是服务调用,都需要写健康检查接口。前面写了我们健康检查地址是/consul/health,这里要开放个接口,让consul来检查身体。
package cn.pomit.springbootwork.consulclient.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/consul")
public class HealthWeb {
@RequestMapping(value = "health", method = { RequestMethod.GET })
public String health() {
return "check health";
}
}
如果我们使用Ribbon做服务调用,需要使用RestTemplate,这个RestTemplate是标识为负载均衡的。我们来调用上一篇提供的ip服务:
IpInfoService :
package cn.pomit.springbootwork.consulclient.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import cn.pomit.springbootwork.consulclient.model.ResultModel;
@Service
public class IpInfoService {
/**
* 第一个consulServer是配置文件种的spring.application.name,第二个consulApi是controller中配置的路径
*/
public static String remoteIpServiceUrl = "http://consulServer/consulApi/ip";
@Autowired
private RestTemplate restTemplate;
public ResultModel getIpInfo() {
ResponseEntity<ResultModel> ipModel = restTemplate.getForEntity(remoteIpServiceUrl, ResultModel.class);
return ipModel.getBody();
}
}
这里,第一个consulServer是服务提供方配置文件种的spring.application.name,第二个consulApi是服务提供方的controller中配置的路径。我们使用统一的实体ResultModel进行数据接收转换。
如果我们使用Feign做服务调用,写法就和controller中写法类似,需要注意的是,如果带参数,需要使用@RequestParam("")标识参数名 :
IpInfoService :
package cn.pomit.springbootwork.consulfeign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import cn.pomit.springbootwork.consulfeign.model.ResultModel;
@FeignClient("consulServer")
public interface IpInfoService {
@RequestMapping(method = RequestMethod.GET, value = "/consulApi/ip", consumes = "application/json")
public ResultModel getIpInfo();
}
这里,@FeignClient中的consulServer是服务提供方配置文件种的spring.application.name,/consulApi/ip中的consulApi是服务提供方的controller中配置的路径。方法尽量和服务提供方的方法一样。
ConsulClientRest :
package cn.pomit.springbootwork.consulclient.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import cn.pomit.springbootwork.consulclient.model.ResultModel;
import cn.pomit.springbootwork.consulclient.service.IpInfoService;
@RestController
@RequestMapping("/consulClient")
public class ConsulClientRest {
@Autowired
IpInfoService ipInfoService;
@RequestMapping(value = "/ip", method = { RequestMethod.GET })
public ResultModel ip() {
return ipInfoService.getIpInfo();
}
}
过程中用到了ResultModel实体和ResultCode枚举类,是和上一篇中的实体对应的,作为统一的实体来用。
ResultModel:
ResultCode:
其他完整实体可以在《品茗IT-SpringCloud技术指南系列(五)服务注册发现之Consul服务调用》查看。
Spring组件化构建
SpringBoot组件化构建
SpringCloud服务化构建