Spring Cloud(Dalston.SR5)--Feign 声明式REST客户端

Posted 追寻自由的路途

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud(Dalston.SR5)--Feign 声明式REST客户端相关的知识,希望对你有一定的参考价值。

Spring Cloud 对 Feign 进行了封装,集成了 Ribbon 并结合 Eureka 可以实现客户端的负载均衡,Spring Cloud 实现的 Feign 客户端类名为 LoadBalancerFeignClient,在该类中,维护着与 SpringClientFactory 相关的实例,通过SpringClientFactory 可以获取负载均衡器,负载均衡器会根据一定的规则来选取处理请求的服务器,最终实现负载均衡功能。

集成了 Hystrix 增加了服务容错处理,并为 Feign 的使用提供了各种默认属性,例如编码器、解码器、日志、注解翻译器、实例创建者和客户端,我们可以简单的使用 Feign,也可以增加自定义的配置,下面我们在 Spring Cloud 中使用 Feign 示例如下:

  • 创建项目

    创建名称为 spring-cloud-feign-client 的 Spring Cloud 项目,修改 POM.xml 中增加以下依赖项:

    <?xmlversion="1.0"encoding="UTF-8"?>

    <projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    ? ?

    <groupId>org.lixue</groupId>

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

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>

    ? ?

    <name>spring-cloud-feign-client</name>

    <description>DemoprojectforSpringBoot</description>

    ? ?

    <parent>

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

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

    <version>1.5.4.RELEASE</version>

    <relativePath/><!--lookupparentfromrepository-->

    </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.SR5</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>

    ? ?

  • 创建 Feign 接口

    在 Spring Cloud 中使用 Feign ,需要使用的是 Spring Cloud 的相关注解,例如 @RequestMapping、@RequestParam 等,而不是 Feign 的注解,创建 HelloWorldClient 接口,使用 @FeignClient 注解来标注服务名称(调用服务的 spring.application.name 属性),使用 @RequestMapping 来标注 REST 服务的相关属性;@RequestParam 和 @PathVariable 注解标注请求参数

    package org.lixue;

    ? ?

    import org.springframework.cloud.netflix.feign.FeignClient;

    import org.springframework.http.MediaType;

    import org.springframework.web.bind.annotation.PathVariable;

    import org.springframework.web.bind.annotation.RequestMapping;

    import org.springframework.web.bind.annotation.RequestMethod;

    import org.springframework.web.bind.annotation.RequestParam;

    ? ?

    @FeignClient("helloworld-provider")

    public interface HelloWorldClient{

    @RequestMapping(path="/speak?body={body}",method=RequestMethod.GET)

    String speak(@RequestParam(value="body",required=false) String body);

    ? ?

    @RequestMapping(path="/person/{personId}",method=RequestMethod.GET,

    produces=MediaType.APPLICATION_JSON_UTF8_VALUE)

    Person findById(@PathVariable("personId")Integer personId);

    ? ?

    @RequestMapping(path="/person/create",method=RequestMethod.POST,

    consumes=MediaType.APPLICATION_JSON_UTF8_VALUE,

    produces=MediaType.APPLICATION_JSON_UTF8_VALUE)

    ReturnValue create(Person person);

    }

    ? ?

  • 启动类启用 Feign

    Feign 集成了 Ribbon 并结合 Eureka 可以实现客户端的负载均衡,因此在启动类我们需要启动 Eureka客户端和 Feign,使用 @EnableEurekaClient 启用 Eureka 客户端;使用 @EnableFeignClients 启用 Feign

    package org.lixue;

    ? ?

    import org.springframework.boot.SpringApplication;

    import org.springframework.boot.autoconfigure.SpringBootApplication;

    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

    import org.springframework.cloud.netflix.feign.EnableFeignClients;

    ? ?

    @SpringBootApplication

    @EnableEurekaClient

    @EnableFeignClients

    public class SpringCloudFeignClientApplication{

    public static void main(String[]args){

    SpringApplication.run(SpringCloudFeignClientApplication.class,args);

    }

    }

    ? ?

  • 增加配置

    Feign 集成了 Ribbon 并结合 Eureka 可以实现客户端的负载均衡,因此需要增加 Eureka 相关配置,指定 eureka 服务注册中心的地址

    ##配置应用名称

    spring:

    application:

    name:spring-cloud-feign-client

    #配置服务端口

    server:

    port:8070

    #设置eureka服务注册中心的地址,如果多个以逗号分割

    eureka:

    client:

    service-url:

    defaultZone:http://eurekaserver01:9000/eureka/,http://eurekaserver02:9000/eureka/

    ? ?

  • 创建 REST 服务

    在调用服务时,只需要使用 @Autowired 注解标注 Feign 接口 HelloWorldClient , Spring Cloud 会帮我们创建和维护客户端实例

    package org.lixue;

    ? ?

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.http.MediaType;

    import org.springframework.web.bind.annotation.*;

    ? ?

    @RestController

    public class InvokerController{

    ? ?

    @Autowired

    private HelloWorldClient helloWorldClient;

    ? ?

    @RequestMapping(path="/invokerSpeak",method=RequestMethod.GET)

    public String invokerSpeak(@RequestParam(name="body",required=false)String body){

    return helloWorldClient.speak(body);

    }

    ? ?

    @RequestMapping(path="/invokerFindByID/{personID}",method=RequestMethod.GET,

    produces=MediaType.APPLICATION_JSON_UTF8_VALUE)

    public Person invokerFindByID(@PathVariable("personID")Integer personID){

    return helloWorldClient.findById(personID);

    }

    ? ?

    @RequestMapping(path="/invokerCreate",method=RequestMethod.GET,

    produces=MediaType.APPLICATION_JSON_UTF8_VALUE)

    ReturnValue invokerCreate(){

    Person newPerson=new Person();

    newPerson.setId(3434);

    newPerson.setAge(34);

    newPerson.setName("343434");

    newPerson.setMessage("33333333333333333");

    return helloWorldClient.create(newPerson);

    }

    }

    ? ?

  • 测试验证

    启动 eureka-server 和 service-provider 项目,启动该项目后,访问地址 http://localhost:8070/invokerSpeak 可以查看到访问,如果启动了多个 service-provider ,多次刷新可以看到,具体的服务调用被轮询调用。

日志配置

启用服务的 Feign 日志,增加配置 Bean 如下:

package org.lixue;

? ?

import feign.Logger;

import org.springframework.context.annotation.Bean;

? ?

public class MyFeignConfiguration{

@Bean

publicLogger.Level level(){

returnLogger.Level.FULL;

}

}

在 Feign 接口的 @FeignClient 注解中,增加 configuration 指向到创建的配置类:

@FeignClient(value="helloworld-provider",configuration=MyFeignConfiguration.class)

public interface HelloWorldClient{

//其他代码如上

}

修改 src/main/resources 目录下的 application.yml 增加日志级别配置:

logging:

level:

org.lixue.HelloWorldClient: debug

? ?

此时就可以看到请求日志的输出,如下:

2018-04-06 12:43:24.578 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] ---> GET http://helloworld-provider/speak HTTP/1.1

2018-04-06 12:43:24.581 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] ---> END HTTP (0-byte body)

2018-04-06 12:43:25.112 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] <--- HTTP/1.1 200 (529ms)

2018-04-06 12:43:25.112 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] content-length: 21

2018-04-06 12:43:25.113 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] content-type: text/plain;charset=UTF-8

2018-04-06 12:43:25.113 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] date: Fri, 06 Apr 2018 04:43:25 GMT

2018-04-06 12:43:25.113 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] x-application-context: helloworld-provider:8001

2018-04-06 12:43:25.113 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak]

2018-04-06 12:43:25.118 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] hello world port:8001

2018-04-06 12:43:25.118 DEBUG 3968 --- [nio-8070-exec-4] org.lixue.HelloWorldClient : [HelloWorldClient#speak] <--- END HTTP (21-byte body)

? ?

默认配置

Spring Cloud 为 Feign 的使用提供了各种默认属性,默认情况下,Spring 将会为 Feign 的属性提供以下 Bean 来实现 Feign 的调用

Bean 类型

Bean 名称

实现类

说明

Decoder

feignDecoder

ResponseEntityDecoder

解码器

Encoder

feignEncoder

SpringEncoder

编码器

Logger

feignLogger

Slf4jLogger

日志

Contract

feignContract

SpringMvcContract

注解翻译器

Feign.Builder

feignBuilder

HystrixFeign.Builder

Feign 实例创建者

Client

feignClient

??

Feign 客户端,启用 Ribbon 实现类为LoadBalancerFeignClient 否则为 Feign 默认实现类

Logger.Level

自命名

没有默认提供,只需要提供该类型的 Bean 即可

Retryer

自命名

没有默认提供,只需要提供该类型的 Bean 即可

ErrorDecoder

自命名

没有默认提供,只需要提供该类型的 Bean 即可

Request.Options

自命名

没有默认提供,只需要提供该类型的 Bean 即可

RequestInterceptor

自命名

没有默认提供,只需要提供该类型的 Bean 即可

? ?

以上是关于Spring Cloud(Dalston.SR5)--Feign 声明式REST客户端的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud(Dalston.SR5)--Zuul 网关-Hystrix 回退

Spring Cloud(Dalston.SR5)--Hystrix 断路器-缓存

Spring Cloud(Dalston.SR5)--Config 集群配置中心-刷新配置

Spring Cloud(Dalston.SR5)--Feign 与 Hystrix 断路器整合

Spring Cloud(Dalston.SR5)--Zuul 网关-微服务集群

Spring Cloud(Dalston.SR5)--Feign 声明式REST客户端