基于HTTP的客户端经常被用作微服务的消费者,这类客户端往往有着平台无关性、语言无关性等特征,而被社区广泛支持,各类HTTP客户端框架也是层出不穷,下面将着重介绍常见的消费模式。
一:服务直连模式
服务直连模式是最容易理解的,例如,我们在浏览器里面访问某篇文章,我们知道这篇文章的URL,就能直接通过URL访问到想要的资源。
例子:
@Service
public class WeatheDatarServiceImpl implements WeatheDataService{
@Autowired
private RestTemplate restTemplate ;
private WeatherResponse getWeatherData(String uri){
ResponseEntity<String> response=restTemplate .getForEntity(uri,String.class);
//....
}
//...
}
服务直连模式具有以下特点:
1.简洁明了
2.平台语言无关性
缺点:一旦URL不可用,无法保证服务的可用性,所以生产环境中比较少用。
二:客户端的发现模式
客户端发现模式是一种由客户端来决定相应服务实例的网络位置的解决方案,原理如下:
1.当服务实例启动后,将自己的位置信息提交到服务注册表(Service Registry)中。服务注册表维护着所有可用的服务实例的列表。
2.客户端从服务注册表进行查询,来获取可用的服务实例
3.在选取可用的服务实例的过程中,客户端自行使用负载均衡算法从多个实例中选择一个,然后发出请求。
客户端发现模式架构:
服务注册表中的实例也是动态变化的。当有新的实例启动时,实例会将实例信息注册到服务注册表中;当实例下线或不可用时,服务注册表也能及时感知到,并将不可用实例及时从服务注册表中清除。服务注册表可以采取类似于心跳等机制来实现对服务实例的感知。
客户端发现模式优点:该模式相对直接,除了服务注册外,其他部分基本无须做改动。此外,由于客户端已经知晓所有可用的服务实例,所以能够针对特定应用来实现智能的负载均衡。
客户端发现模式缺点:客户端需要与服务注册表进行绑定,要针对服务端用到的每个编程语言和框架,来实现客户端的服务发现逻辑。
三:服务端发现模式
该模式是客户端通过负载均衡向某个服务提出请求,负载均衡器查询服务注册表,并将请求转发到可用的服务实例。同客户端发现模式类似,服务实例在服务注册表中注册或销毁。
服务端发现模式架构
与客户端发现模式最大的区别在于:负载均衡不是由客户端来做,而是在服务端实现,负载均衡器是独立部署在服务端的。
常见的微服务消费者框架主要有 HttpClient、Ribbon、Feign等,下面就实际情况来创建一个项目
项目结构图:
pom文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.csq.study</groupId>
<artifactId>springBoot-eureka-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.14.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring.cloud.version>Edgware.SR5</spring.cloud.version>
<quartz.version>2.0.0.RELEASE</quartz.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- Eureka服务-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
</project>
配置文件:
#端口号
server.port=8088
#应用名称
spring.application.name=springBoot-eureka-client
#注册服务器的URL
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
#请求服务时的超时时间
#feign.client.config.feignName.connect-timeout=5000
#读数据时的超时时间
#feign.client.config.feignName.read-timeout=5000
#feign.hystrix.enabled: false
controller层:
package com.csq.study.springboot.controller;
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 com.csq.study.springboot.service.CityClient;
@RestController
public class CityController {
@Autowired
private CityClient cityClient;
@RequestMapping(value="/cities", method=RequestMethod.GET)
public String listCity() {
//通过Feign客户端来查找
String body=cityClient.listCity();
return body;
}
}
service接口
package com.csq.study.springboot.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient("springBoot-city")
public interface CityClient {
@RequestMapping(value="/cities", method=RequestMethod.GET)
String listCity();
}
启动类:
package com.csq.study.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
/*
* @SpringBootApplication注解声明Spring Boot应用
* 作用等同于@Configuration, @EnableAutoConfiguration, @ComponentScan,
* 简化Spring配置
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
在我们启动这个项目之前,要先启动注册中心(https://blog.csdn.net/FindHuni/article/details/92613639)
然后在启动:springBoot-city (https://blog.csdn.net/FindHuni/article/details/91534477)
然后启动该项目。在注册中I心检查项目是否启动完成
然后访问:http://localhost:8088/cities
可以看到以下截图表示成功