在微服务架构中,多个松耦合的服务协同工作,每项服务都专注于一个目的,并对相关行为和数据高内聚。

上述定义描述了微服务的设计原则:

  • 单一原则:每项服务专注于一个目的并做好。
  • 松耦合:服务之间没有太多的联系。
  • 高内聚:每个服务将所有相关行为与数据封装在一起。

所以在微服务松耦合的设计原则下,会存在一个基本的问题,服务之间如何通信呢?解决方案那就是:远程调用。

什么是远程调用呢?

从物理层次可以简单理解为,调用者和被调用者可能不在同一台主机上,但是它们之间需要相互调用其接口方法,这就是远程调用。

从微服务层次可以理解为,服务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入门」

  • (负载均衡)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)。

微服务远程调用「Feign入门」

如何使用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入门」

在使用Feign过程中,还会有一些意想不到的坑,后面的文章再详细说。

文章中 demo Git地址:gitee.com/renxiaoshi/…