在实际开发中,对于服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以我们通常会针对各个微服务自行封装一些客户端类来包装这些依赖服务的调用,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. 在Hadoop2.2基础上安装Spark(伪分布式)

    没想到,在我的hadoop2.2.0小集群上上安装传说中的Spark竟然如此顺利,可能是因为和搭建Hadoop时比较像,更多需要学习的地方还是scala编程和RDD机制吧 总之,开个好头 原来的集群: ...

  2. 我的Java设计模式-单例模式

    就算不懂设计模式的兄弟姐妹们,想必也听说过单例模式,并且在项目中也会用上.但是,真正理解和熟悉单例模式的人有几个呢?接下来我们一起来学习设计模式中最简单的模式之一--单例模式 一.为什么叫单例模式? ...

  3. Unity引擎与C#脚本简介

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 由 QQ会员技术团队 发布在云+社区 1. Unity编辑器基础 从原理上讲,游戏开发就是将一系列变动的场景呈现在玩家面前,并根据玩家的输入 ...

  4. 2_Add Two Numbers --LeetCode

    原题如下: 思路:在一个while中遍历两个链表,直到最长的链表为空,或者没有进位.每一步获取两个链表对应的结点的值a,b,然后相加a+b.如果上一步又进位,那就加a+b+1,若由于进位加1后还产生进 ...

  5. FusionCharts 3D环饼图报错

    1.在设计FusionCharts 3D环饼图时,出现错误,图显示不出来,具体错误如下图: 2.经过检查,发现声明的变量和下面引用的变量不一致 var doughnut2D = new FusionC ...

  6. 常用YUV转RGB代码

    常用YUV转RGB [java] view plaincopyprint? public class YuvToRGB { private static int R = 0; private stat ...

  7. Java利用递归算法统计1-6的数组排列组合数

    Java利用递归算法统计1-6的数组排列组合数 1.设计源码 /** * @Title:ArrayCombination.java * @Package:com.you.data * @Descrip ...

  8. 芝麻HTTP:Python爬虫实战之爬取百度贴吧帖子

    本篇目标 1.对百度贴吧的任意帖子进行抓取 2.指定是否只抓取楼主发帖内容 3.将抓取到的内容分析并保存到文件 1.URL格式的确定 首先,我们先观察一下百度贴吧的任意一个帖子. 比如:http:// ...

  9. jquery中的下拉框

    1.1select获取选中的value值 <label for="select"> <select id="key_RedemptionMode&quo ...

  10. 关于webpack,打包时遇到的错误

    最近在研究webpack这玩意,然后遇到一个问题,执行npm run build的时候,出现下面这个问题,各种搜索后,各种尝试,都没解决 运行时报错ERROR in ./src/app.vue Mod ...