在微服务架构中,多个松耦合的服务协同工作,每项服务都专注于一个目的,并对相关行为和数据高内聚。
上述定义描述了微服务的设计原则:
- 单一原则:每项服务专注于一个目的并做好。
- 松耦合:服务之间没有太多的联系。
- 高内聚:每个服务将所有相关行为与数据封装在一起。
所以在微服务松耦合的设计原则下,会存在一个基本的问题,服务之间如何通信呢?解决方案那就是:远程调用。
什么是远程调用呢?
从物理层次可以简单理解为,调用者和被调用者可能不在同一台主机上,但是它们之间需要相互调用其接口方法,这就是远程调用。
从微服务层次可以理解为,服务A和服务B是两个不同的微服务,服务A要使用服务B的方法,服务A是调用方,服务B是被调用方。
远程调用方式
常见的远程调用的方式有2种:
- HTTP:网络传输协议,基于TCP。规定了数据传输的格式,远程调用时,方式简单,没有规定语言,可跨语言、跨平台,通用性强。但是消息封装较为臃肿。代表作:REST风格。
- RPC:远程过程调用通信协议,基于TCP。可以自定义数据格式,偏向于底层,简洁,通信速度快,效率高,但是限制于开发语言环境。代表作:webservice、dubbo。
这两种方式怎么选择呢?
- 如果开发技术环境多变,需要跨平台、跨语言,则推荐使用HTTP。
- 如果要求效率高,并且开发过程中使用统一的技术栈,则推荐使用RPC。
远程调用组件
在平时开发过程中,常用的组件有:
- HttpClient:是客户端的http通信实现库,这个类库的作用是接收和发送http报文,使用这个类库,它相比传统的 HttpURLConnection,增加了易用性和灵活性,我们对于http的操作会变得简单一些。
- Okhttp:一个处理网络请求的开源项目,是安卓端最火的轻量级框架,由 Square 公司贡献,用于替代 HttpUrlConnection 和 Apache HttpClient。OkHttp 拥有简洁的 API、高效的性能,并支持多种协议。
- HttpURLConnection:是 Java 的标准类,它继承自 URLConnection,可用于向指定网站发送 GET 请求、POST 请求。使用比较复杂,不像HttpClient那样容易使用。
- RestTemplate:是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率。
其中,使用RestTemplate来完成远程调用比较常见,但是在服务中如果大量使用的话,配置会比较复杂,下面主要介绍一个比上面这些使用更简单,更方便的组件,那便是微服务治理组件:Feign。
Feign是什么呢?
Feign是Netflix开发的声明式、模板化的Http客户端。
Feign 不做任何请求处理,通过处理注解相关信息生成 Request,并对调用返回的数据进行解码,从而实现简化 HTTP API 的开发。
- (负载均衡)Feign是一种实现负载均衡的框架,它底层封装了Riboon和RestTemplate。
- (快速熔断)Feign底层也集成了Hystix(服务熔断组件),它默认实现负载均衡后的快速熔断回退。
- Feign本身不支持SpringMVC注解,它有自己的注解。
它的优势,做到了使用HTTP请求远程服务时向调用本地方法一样,和Dubbo差不多,调用者直接调用接口方法调用被调用者,不需要通过常规的HttpClient构造各种请求数据和解析响应数据。
自2019年后,Feign组件已停止更新,便有了它的升级版:OpenFeign。
OpenFeign又是什么呢?
OpenFeign 是 SpringCloud 在Feign 的基础上增加了对 SpringMVC 注解的支持,如 @RequestMapping 注解。
OpenFeign 的@FeignClient 可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中的负载均衡并远程调用其他服务。
OpenFeign 和 Feign 的区别:
Feign | OpenFeign | |
---|---|---|
引用依赖 | spring-cloud-starter-feign | spring-cloud-starter-openfeign |
使用方式 | 不支持SpringMVC的注解 | 支持SpringMVC注解 |
举个栗子,入个门
环境准备
version | |
---|---|
Spring Boot | 2.1.0.RELEASE |
Spring Cloud | Greenwich.SR5 |
Spring Cloud Alibaba | 2.1.2.RELEASE |
注册中心使用Nacos,生产者工程(springboot-feign-produce)和消费者工程(springboot-feign-consume)。
如何使用Nacos,这里不再多说,可以看以前的文章:微服务「Nacos」
生产者
启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ProduceApplication {
public static void main(String[] args) {
SpringApplication.run(ProduceApplication.class, args);
System.out.println(" ヾ(◍∇◍)ノ゙ Application启动成功 ヾ(◍∇◍)ノ゙");
}
}
测试接口
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping("/hello")
public String produce(String name){
System.out.println("From Consumer: " + name);
return "hello " + name;
}
}
消费者
启动类
除了注释Nacos注册,还需要注释@EnableFeignClient
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumeApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumeApplication.class, args);
System.out.println(" ヾ(◍∇◍)ノ゙ Application启动成功 ヾ(◍∇◍)ノ゙");
}
}
定义消费服务接口
@FeignClient("springboot-feign-produce")
public interface TestFeignClient {
@RequestMapping("/feign-produce/test/hello")
String produce(@RequestParam String name);
}
测试接口
@RestController
@RequestMapping("/test")
public class TestController {
@Resource
private TestFeignClient testFeignClient;
@RequestMapping("/hello")
public String consume(String name){
System.out.println("to consumer: " + name);
String produce = testFeignClient.produce(name);
return "From Produce : " + produce;
}
}
请求: http://localhost:10002/feign-consume/test/hello?name=shiyunxi ,测试接口
在使用Feign过程中,还会有一些意想不到的坑,后面的文章再详细说。
文章中 demo Git地址:gitee.com/renxiaoshi/…