在实际开发中,对于服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以我们通常会针对各个微服务自行封装一些客户端类来包装这些依赖服务的调用,Spring Cloud Feign 在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,我们只需要创建一个接口并用注解的方式来配置他,即可完成对服务提供方的接口绑定,简化了在使用 Spring Cloud Ribbon 时自行封装服务调用客户端的开发量。

快速入门

  • 首先创建一个 Spring Cloud 的基础工程,并增加 spring-cloud-starter-eureka 依赖 和 spring-cloud-starter-feign 依赖,示例代码如下:

    <?xml
    version="1.0"
    encoding="UTF-8"?>

    <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>org.lixue</groupId>

    <artifactId>eureka-feign-consumer</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>

    <name>eureka-feign-consumer</name>

    <description>Demo project for Spring Boot</description>

    <parent>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-parent</artifactId>

    <version>1.5.6.RELEASE</version>

    <relativePath/>
    <!-- lookup parent from repository -->

    </parent>

    <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

    <java.version>1.8</java.version>

    <spring-cloud.version>Dalston.SR3</spring-cloud.version>

    </properties>

    <dependencies>

    <dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-eureka</artifactId>

    </dependency>

    <dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-feign</artifactId>

    </dependency>

    <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-test</artifactId>

    <scope>test</scope>

    </dependency>

    </dependencies>

    <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>

    <build>

    <plugins>

    <plugin>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-maven-plugin</artifactId>

    </plugin>

    </plugins>

    </build>

    </project>

  • 创建应用主类 EurekaFeignConsumerApplication 并通过 @EnableFeignClients 注解开启 Spring Cloud Feign 功能,使用 @EnableDiscoveryClient 注解开启 Eureka的服务发现,代码如下:

    @EnableFeignClients

    @EnableDiscoveryClient

    @SpringBootApplication

    public class EurekaFeignConsumerApplication {

    public static
    void
    main(String[] args) {

    SpringApplication.run(EurekaFeignConsumerApplication.class, args);

    }

    }

  • 定义 HelloWorldService 接口,通过 @FeignClient 注解指定服务名来绑定服务,然后再使用Spring MVC 的注解来绑定具体该服务提供的 REST 接口,代码如下:

    @FeignClient ("ORG.LIXUE.HELLOWORLD")

    public interface HelloWorldService {

    @RequestMapping ("/hi")

    String hi();

    }

  • 在需要调用服务的位置,使用 @Autowired
    直接注入
    HelloWorldService 实例,并使用该接口实例调用方法 hi 来完成 /hi 接口的调用,示例代码如下:

    @RestController

    public class FeignConsumerController {

    @Autowired

    HelloWorldService helloWorldService;

    @RequestMapping ("/hi")

    public String hi() {

    return helloWorldService.hi();

    }

    }

  • 在 application.yml 中需要指定服务注册中心,并定义自身的服务名和端口,示例如下:

    server:

    port: 9200

    eureka:

    client:

    service-url:

    defaultZone: http://eurekaserver2:9002/eureka,http://eurekaserver1:9001/eureka

    spring:

    application:

    name: eureka-feign-consumer

  • 启动服务注册中心以及二个ORG.LIXUE.HELLOWORLD服务,然后启动 eureka-feign-consumer ,此时发送几次 GET 请求到 http://localhost:9200/hi ,可以正确的返回 Hello World hi 9100 或者 Hello World hi 9101 ,可以看到Feign实现的消费者,依然是利用 Ribbon 维护了针对 ORG.LIXUE.HELLOWORLD服务列表信息,并且通过轮询实现了客户端负载均衡。

参数绑定

在入门示例中我们实现的是一个不带参数的
REST
服务绑定,然而现实系统中的各种业务接口要比他复杂很多,我们会在HTTP的各个位置传入各种不同类型的参数,并且在返回请求响应的时候也可能是一个复杂对象结构,因此我们需要使用
Feign
来对不同形式的参数进行绑定

  • @RequestParam 注解:常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String--> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定

    @RequestMapping (value = "/hi1", method = RequestMethod.GET)

    public String hi(@RequestParam ("name") String name) {

    return
    "Hello World hi " + port + " name " + name;

    }

  • @CookieValue
    注解:可以把Request header中关于cookie的值绑定到方法的参数上

    @RequestMapping("/displayHeaderInfo.do")

    public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie)  {

    //...

    }

  • @RequestBody 注解:用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上

    @RequestMapping (value = "/hi2", method = RequestMethod.POST)

    public String hi(@RequestBody User user) {

    return
    "Hello World hi " + port + "\tUser=" + user;

    }

    注意:User 类必须有默认构造函数

  • @RequestHeader 注解:可以把Request请求header部分的值绑定到方法的参数上

    @RequestMapping("/displayHeaderInfo.do")

    public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,

    @RequestHeader("Keep-Alive") long keepAlive)  {

    //...

    }

  • @PathVariable 注解:当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable
    注解绑定它传过来的值到方法的参数上,示例代码如下:

    @Controller

    @RequestMapping("/owners/{ownerId}")

    public class RelativePathUriTemplateController {

    @RequestMapping("/pets/{petId}")

    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

    // implementation omitted

    }

    }

继承特性

在Spring
Cloud
Feign 中,提供了继承特性来帮助我们构建相应的服务客户端不安定接口和服务控制器,进一步减少编码量,示例如下:

  • 创建一个基础的 Maven 工程,命名为
    service-contract,由于需要使用到 Spring MVC 的注解,因此在 pom.xml 中引入 spring-boot-starter-web 依赖,具体内容如下:

    <?xml
    version="1.0"
    encoding="UTF-8"?>

    <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>org.lixue</groupId>

    <artifactId>service-contract</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>

    <name>service-contract</name>

    <description>Demo project for Spring Boot</description>

    <parent>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-parent</artifactId>

    <version>1.5.6.RELEASE</version>

    <relativePath/>
    <!-- lookup parent from repository -->

    </parent>

    <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

    <java.version>1.8</java.version>

    <spring-cloud.version>Dalston.SR3</spring-cloud.version>

    </properties>

    <dependencies>

    <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

    </dependency>

    </dependencies>

    </project>

  • 在项目中创建服务需要使用的实体类和服务接口,代码如下:

    public class User {

    private String name;

    private
    int age;

    // setter

    getter
    方法

    @Override

    public String toString() {

    return
    "name=" + name + "\tage=" + age;

    }

    }

    @RequestMapping("/hello")

    public interface HelloWorldService {

    @RequestMapping (value = "/hi", method = RequestMethod.GET)

    String hi();

    @RequestMapping (value = "/hi1", method = RequestMethod.GET)

    String hi(@RequestParam ("name") String name);

    @RequestMapping (value = "/hi2", method = RequestMethod.POST)

    String hi(@RequestBody User user);

    }

  • 在服务的具体实现项目中增加 service-contract 的依赖,并且实现服务需要继承上面的 HelloWorldService 接口,并重写接口方法实现具体的服务实现

    @RestController

    public class HelloWorldController implements HelloWorldService {

    @Value ("${server.port}")

    int port;

    @Override

    public String hi() {

    return
    "hi port " + port;

    }

    @Override

    public String hi(String name) {

    return
    "hi port " + port + " name " + name;

    }

    @Override

    public String hi(@RequestBody User user) {

    return
    "hi port " + port + " user " + user;

    }

    }

  • 在具体的消费项目中增加 service-contract 依赖增加接口
    HelloWorldServiceProxy ,继承
    service-contract 项目中的
    HelloWorldService
    并使用 @FeignClient 注解来声明调用服务名称

    @FeignClient ("ORG.LIXUE.HELLOWORLD")

    public interface HelloWorldServiceProxy extends HelloWorldService {

    }

  • 在需要调用服务的位置,使用 @Autowired
    直接注入
    HelloWorldServiceProxy 实例,并使用该接口实例调用方法 hi 来完成 /hi 接口的调用,示例代码如下:

    @RestController

    public class FeignConsumerController {

    @Autowired

    HelloWorldService helloWorldService;

    @RequestMapping ("/hi")

    public String hi() {

    User user = new
    User();

    user.setName("liyong");

    user.setAge(3434);

    StringBuilder stringBuilder = new
    StringBuilder();

    stringBuilder.append("hi=" + helloWorldServiceProxy.hi()).append("<br/>");

    stringBuilder.append("hi1=" + helloWorldServiceProxy.hi("lixue")).append("<br/>");

    stringBuilder.append("hi2=" + helloWorldServiceProxy.hi(user)).append("<br/>");

    return stringBuilder.toString();

    }

    }

  • 在 application.yml 中需要指定服务注册中心,并定义自身的服务名和端口,示例如下:

    server:

    port: 9200

    eureka:

    client:

    service-url:

    defaultZone: http://eurekaserver2:9002/eureka,http://eurekaserver1:9001/eureka

    spring:

    application:

    name: eureka-feign-consumer

  • 启动服务注册中心以及二个ORG.LIXUE.HELLOWORLD服务,然后启动 eureka-feign-consumer ,此时发送几次 GET 请求到 http://localhost:9200/hi ,可以正确的返回 Hello World hi 9100 或者 Hello World hi 9101 ,可以看到Feign实现的消费者,依然是利用 Ribbon 维护了针对 ORG.LIXUE.HELLOWORLD服务列表信息,并且通过轮询实现了客户端负载均衡。

笔记:Spring Cloud Feign 声明式服务调用的更多相关文章

  1. Spring Cloud Feign 声明式服务调用

    目录 一.Feign是什么? 二.Feign的快速搭建 三.Feign的几种姿态 参数绑定 继承特性 四.其他配置 Ribbon 配置 Hystrix 配置 一.Feign是什么? ​ 通过对前面Sp ...

  2. Spring Cloud Feign声明式服务调用(转载)+遇到的问题

    转载:原文 总结: 1.pom添加依赖 2.application中填写正确的eureka配置 3.启动项中增加注解 @EnableFeignClients 4.填写正确的调用接口 通过原文使用Fei ...

  3. Spring Cloud 2-Feign 声明式服务调用(三)

    Spring Cloud Feign  1. pom.xml 2. application.yml 3. Application.java 4. Client.java 简化RestTemplate调 ...

  4. spring cloud 系列第4篇 —— feign 声明式服务调用 (F版本)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.feign 简介 在上一个用例中,我们使用ribbon+restTem ...

  5. Feign声明式服务调用

    Feign是一种声明式.模板化的HTTP客户端(仅在Application Client中使用).声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求. Spring Clo ...

  6. SpringCloud微服务实战二:Spring Cloud Ribbon 负载均衡 + Spring Cloud Feign 声明式调用

    1.Spring Cloud Ribbon的作用 Ribbon是Netflix开发的一个负载均衡组件,它在服务体系中起着重要作用,Pivotal将其整合成为Spring Cloud Ribbon,与其 ...

  7. Spring Cloud07: Feign 声明式接口调用

    一.什么是Feign Feign也是去实现负载均衡,但是它的使用要比Ribbon更加简化,它实际上是基于Ribbon进行了封装,让我们可以通过调用接口的方式实现负载均衡.Feign和Ribbon都是由 ...

  8. SpringCloud实战-Feign声明式服务调用

    在前面的文章中可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率 ...

  9. Spring Cloud Feign 优雅的服务调用

    Fegin 是由NetFlix开发的声明式.模板化HTTP客户端,可用于SpringCloud 的服务调用.提供了一套更优雅.便捷的HTTP调用API,并且SpringCloud整合了Fegin.Eu ...

随机推荐

  1. H3C三层交换机配置IP

    1.直接在物理端口上设置IP地址. int f1/0/1 port link-mode route #链路模式采用路由 ip add 192.168.10.1 24 ospf network0type ...

  2. C#扩展方法类库StringExtensions

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. hdu5730 Shell Necklace

    重温了这道cdq+FFT 讲白了就是不断对 dp[l~mid] 和 sh[1~r] 进行fft 得到 dp[mid+1~r] #include<bits/stdc++.h> using n ...

  4. 使用WebApiClient请求和管理Restful Api

    前言 本篇文章的内容是WebApiClient应用说明篇,如果你没有了解过WebApiClient,可以先阅读以下相关文章: WebApi client 的面向切面编程 我来给.Net设计一款Http ...

  5. Linux下使用Nginx端口转发出现502错误的一种解决办法

    今天圈里的一个朋友在配置完nfinx80端口转发到5000后,发现一个问题 问题描述: 正确配置了Nginx80端口转5000端口,在CentOS上把.Net core WebAPI站点上传到cent ...

  6. html点小图看大图最快捷的方法

    方法一: <td> <a href="{$vo.show_img}" target="_blank"><img style=&qu ...

  7. tomcat环境配置 Linux 与 Windows

    Windows:例如tomcat安装在 E:\tomcat 需要在环境变量配置:CATALINA_HOME=E:\tomcat CATALINA_BASE= E:\tomcat Linux:例如tom ...

  8. 【learning】kd-tree

    吐槽 kd-tree这个东西很早就听说过了但是qwq一直没有去了解 (原因的话..啊哈哈听说是什么跟二维平面之类的东西有关的所以就怂掉了qwq没错就是怂qwq) 但其实好像..真的很暴力啊qwq知道思 ...

  9. 基于socket实现的简单的聊天程序

    记得八年前第一次使用socket做的一个五子棋程序,需要序列化棋子对象,传递到对方的电脑上. 一个偶然的机会,第二次使用socket做点事情.先看聊天服务器端的实现: 服务器端要实现以下功能:     ...

  10. Micropython TurnipBit 青少年入门编程 交通灯实验

    不知道大家小时候对红绿灯的原理有什么研究过,我是农村的孩子直到初中才见到真实的红绿灯,当时我记得很清楚,在那个路口站了五六分钟就盯着红绿灯变换,搞不清原理,只觉得神奇.现在想来实在可笑,今天写这个的很 ...