springboot+cloud 学习(二)应用间通讯Feign(伪RPC,实则HTTP)

在微服务中,使用什么协议来构建服务体系,一直是个热门话题。 争论的焦点集中在两个候选技术:  RPC or Restful前端

Restful架构是基于Http应用层协议的产物,RPC架构是基于TCP传输层协议的产物。web

网络七层模型

在说RPC和HTTP的区别以前,了解一下七层网络结构模型(虽然实际应用中基本上都是五层),它能够分为如下几层: (从上到下)spring

  • 第一层:应用层。定义了用于在网络中进行通讯和传输数据的接口;
  • 第二层:表示层。定义不一样的系统中数据的传输格式,编码和解码规范等;
  • 第三层:会话层。管理用户的会话,控制用户间逻辑链接的创建和中断;
  • 第四层:传输层。管理着网络中的端到端的数据传输;
  • 第五层:网络层。定义网络设备间如何传输数据;
  • 第六层:链路层。将上面的网络层的数据包封装成数据帧,便于物理层传输;
  • 第七层:物理层。这一层主要就是传输这些二进制数据。

实际应用过程当中,五层协议结构里面是没有表示层和会话层的。应该说它们和应用层合并了。咱们应该将重点放在应用层和传输层这两个层面。由于HTTP是应用层协议,而TCP是传输层协议。apache

RPC

RPC 即远程过程调用(Remote Procedure Call Protocol,简称RPC),像调用本地服务(方法)同样调用服务器的服务(方法)。一般的实现有 XML-RPC , JSON-RPC , 通讯方式基本相同, 所不一样的只是传输数据的格式.springboot

RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式(TCP或者UDP)、序列化方式(XML/JSON/二进制)和通讯细节。开发人员在使用的时候只须要了解谁在什么位置提供了什么样的远程服务接口便可,并不须要关心底层通讯细节和调用过程。服务器

Restful

REST即表述性状态传递(Representational State Transfer,简称REST),是一种软件架构风格。REST经过HTTP协议定义的通用动词方法(GET、PUT、DELETE、POST) ,以URI对网络资源进行惟一标识,响应端根据请求端的不一样需求,经过无状态通讯,对其请求的资源进行表述。知足REST约束条件和原则的架构,就被称为是RESTful架构.网络

 

区别

使用RPC远程服务调用方式与传统http接口直接调用方式的差异在于:架构

1. 从使用方面看,Http接口只关注服务提供方(服务端),对于客户端怎么调用,调用方式怎样并不关心,一般状况下,客户端使用Http方式进行调用时,只要将内容进行传输便可,这样客户端在使用时,须要更关注网络方面的传输,比较不适用与业务方面的开发;而RPC服务则须要客户端接口与服务端保持一致,服务端提供一个方法,客户端经过接口直接发起调用,业务开发人员仅须要关注业务方法的调用便可,再也不关注网络传输的细节,在开发上更为高效。app

2. 从性能角度看,使用Http时,Http自己提供了丰富的状态功能与扩展功能,但也正因为Http提供的功能过多,致使在网络传输时,须要携带的信息更多,从性能角度上讲,较为低效。而RPC服务网络传输上仅传输与业务内容相关的数据,传输数据更小,性能更高。负载均衡

3. 从运维角度看,使用Http接口时,经常使用一个前端代理,来进行Http转发代理请求的操做,须要进行扩容时,则须要去修改代理服务器的配置,较为繁琐,也容易出错。而使用RPC方式的微服务,则只要增长一个服务节点便可,注册中心可自动感知到节点的变化,通知调用客户端进行负载的动态控制,更为智能,省去运维的操做。

Feign

Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 建立一个接口并对它进行注解,它具备可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增长了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign.

maven 多模块下的Feign使用

目前个人项目中有2个模块device和equip,每一个模块因为业务的须要拆分红4部分(parent、client、common、server)

 

parent为父项目,基本没什么代码,会定义一些依赖做统一管理,其pom.xml以下

<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.skyworth.tvmanage</groupId>
    <artifactId>management-equip</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>equip</name>
    <description>equip servers</description>

    <modules>
        <module>management-equip-client</module>
        <module>management-equip-common</module>
        <module>management-equip-server</module>
    </modules>

    <!-- 必需要引入 springboot parent ,帮咱们实现了不少jar包的依赖管理 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <!-- 版本集中配置 -->
    <properties>
        <spring.cloud.version>Finchley.RELEASE</spring.cloud.version>
        <management-common.version>0.0.1-SNAPSHOT</management-common.version>
    </properties>

    <!-- cloud -->
    <dependencyManagement>
        <dependencies>
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.skyworth.tvmanage</groupId>
                <artifactId>management-equip-common</artifactId>
                <version>${management-common.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

server部分为业务模块,common为一些公共调用的类,client部分定义向外暴露的接口,client部分pom.xml以下

<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>
  <parent>
    <groupId>com.skyworth.tvmanage</groupId>
    <artifactId>management-equip</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <!-- 向外暴露的接口 client -->
  <artifactId>management-equip-client</artifactId>
  <name>equip-client</name>
  <description>equip servers</description>
  
  <!-- 版本集中配置 -->
    <properties>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.skyworth.tvmanage</groupId>
            <artifactId>management-equip-common</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
</project>

而后,再来看client接口的定义 ManagementEquipClient.class,  @FeignClient里的名称为Eureka里注册的须要调用的服务名称


@FeignClient("MANAGEMENT-EQUIP")
public interface ManagementEquipClient {
    
    @PostMapping("/tvmanage/equip/addEquip")
    public void addEquip(@RequestBody Equip equip);
    
    @RequestMapping(value="/tvmanage/equip/checkEquipExists", method=RequestMethod.GET)
    Integer checkEquipExists(@RequestParam String core,@RequestParam String type,@RequestParam String country);
    
    @RequestMapping(value="/tvmanage/equip/getDefaultScheme", method=RequestMethod.GET)
    Integer getDefaultScheme(@RequestParam String core,@RequestParam String type,@RequestParam String country);
}

 

因为我这里,feign是device调用equip,基本equip部分配置就差很少了,再来看看devcie部分,在device应用主类中经过@EnableFeignClients注解开启Feign功能。

这里须要注意的是@EnableFeignClients的扫包问题,就是***的地址要正确

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages="****")
public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
}

而后在device部分的controller中,声明equip服务,就能够正常调用了

相关文章
相关标签/搜索