spring cloud之feign(四)

来源:互联网 发布:java 调用 jmeter api 编辑:程序博客网 时间:2024/05/19 17:58

1.Feign简介

Feign是一个声明式的Web服务客户端。这使得Web服务客户端的写入更加方便 要使用Feign创建一个界面并对其进行注释。它具有可插入注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持,并使用Spring Web中默认使用的HttpMessageConverters。Spring Cloud集成Ribbon和Eureka以在使用Feign时提供负载均衡的http客户端。

在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端。我们可以使用JDK原生的URLConnection、Apache的Http Client、Netty的异步HTTP Client, Spring的RestTemplate。但是,用起来最方便、最优雅的还是要属Feign了。

Feign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用Feign, 我们可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。

现在为止所进行的 有Rest Rest 服务调用实际上都会出现一个非常尴尬的局面,所有的数据调用和转换都必须由户自己来完成,而我们本身不擅 所有的数据调用和转换都必须由户自己来完成,我们习惯的编程模式是:通过接口来实现业务 长这些,我们习惯的编程模式是:通过接口来实现业务 长这些,我们习惯的编程模式是:通过接口来实现业务 长,这可以通过feign来实现,Feign = RestTempate + HttpHeader Ribbon Eureka综合体 综合体 = 业务接口的自动实例化。

2.使用Feign

2.1 pom.xml中添加

<?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">    <parent>        <artifactId>spring-cloud</artifactId>        <groupId>com.alen</groupId>        <version>0.0.1-SNAPSHOT</version>    </parent>    <modelVersion>4.0.0</modelVersion>    <packaging>jar</packaging>    <artifactId>feign-service</artifactId>    <dependencies>        <!--eureka client -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-eureka</artifactId>        </dependency>        <!--feign支持-->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-feign</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>        </plugins>    </build></project>


2.2 定义接口

为了让Feign知道在调用方法时应该向哪个地址发请求以及请求需要带哪些参数,我们需要定义一个接口:

package com.alen.service;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;/** * 定义一个feign接口,通过@ FeignClient(“服务名”),来指定调用哪个服务 **/@FeignClient(value ="eureka-client")public interface HelloService {    @RequestMapping("/hello")     //必须显示的指定age,不显示还不行      String hello(@RequestParam("age") Integer age);}

A: @FeignClient用于通知Feign组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@Autowired注入。

B: @RequestMapping表示在调用该方法时需要向/group/{groupId}发送GET请求。

C: @PathVariableSpringMVC中对应注解含义相同。

Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里。

在本例中,我们将Feign与Eureka和Ribbon组合使用,@FeignClient(name = "ea")意为通知Feign在调用该接口方法时要向Eureka中查询名为ea的服务,从而得到服务URL。


controller中调用这个接口

@RestControllerpublic class HelloController {    @Autowired    private HelloService  helloService;    /**     * 通过Controller调用远程服务     * @param age     * @return     */    @RequestMapping("/hello")    public String home(@RequestParam Integer age) {        return helloService.hello(age);    }}


2.3 启动类

@SpringBootApplication//通过注解@EnableEurekaClient 表明自己是一个eurekaclient.@EnableEurekaClient//开启Feign的功能@EnableFeignClientspublic class App {   public static void main(String[] args) {      SpringApplication.run(App.class, args);   }}

2.4 application.properties文件

#端口server.port=8075eureka.instance.hostname=localhost#设置eureka服务器所在的地址,查询服务和注册服务都需要依赖这个地址。eureka.client.serviceUrl.defaultZone=http\://localhost\:8081/eureka/#这在以后的服务与服务之间相互调用一般都是根据这个namespring.application.name=feign-service#eureka.client.register-with-eureka=true#eureka.client.fetch-registry=true# 心跳时间,即服务续约间隔时间(缺省为30s)eureka.instance.lease-renewal-interval-in-seconds= 5# 发呆时间,即服务续约到期时间(缺省为90s)eureka.instance.lease-expiration-duration-in-seconds=15     

Feign的源码实现的过程如下:

  • 首先通过@EnableFeignCleints注解开启FeignCleint
  • 根据Feign的规则实现接口,并加@FeignCleint注解
  • 程序启动后,会进行包扫描,扫描所有的@ FeignCleint的注解的类,并将这些信息注入到ioc容器中。
  • 当接口的方法被调用,通过jdk的代理,来生成具体的RequesTemplate
  • RequesTemplate在生成Request
  • Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp
  • 最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。

2.5 .Feign 相关配置

FeignFeignFeign Feign之中最为核心的作用就是将 Rest Rest 服务的信息转换为接口,但是在实际使用之中也需要 考虑到一些配置情况, 例如:数据压缩Rest Rest 的核心本质在于: JSON 数据传输( XMLXMLXML、文本),于是就必须思考一种情况,玩意 、文本),于是就必须思考一种情况,玩意 、文本),于是就必须思考一种情况,玩意 用户发送的数据很大呢? 所以这个时候可考虑修改 application.yml 配置文件对传输数据进行压缩; 配置文件对传输数据进行压缩;

feign:   compression:         request:               mime-types: # 可以被压缩的类型#                 - text/xml#                 - application/xml#                 - application/json                min-request-size: 2048 # 超过2048的字节进行压缩

2、 如果有需要则可以在项目之中开启  feign的相关日志信息(默认不开启) 的相关日志信息(默认不开启) :
修改 application.yml配置文件,追加日志追踪:
logging:     level:#      feign接口包所在位置        cn.mldn.service: DEBUG


修改 FeignClientConfig ,开启日志的输出:

 @Configurationpublic class FeignClientConfig {    @Bean    public Logger.Level getFeignLoggerLevel() {        return feign.Logger.Level.FULL ;    }   }

3. Feign的Encoder、Decoder和ErrorDecoder

Feign将方法签名中方法参数对象序列化为请求参数放到HTTP请求中的过程,是由编码器(Encoder)完成的。同理,将HTTP响应数据反序列化为java对象是由解码器(Decoder)完成的。

默认情况下,Feign会将标有@RequestParam注解的参数转换成字符串添加到URL中,将没有注解的参数通过Jackson转换成json放到请求体中。注意,如果在@RequetMapping中的method将请求方式指定为POST,那么所有未标注解的参数将会被忽略,例如:

@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET)void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName, DataObject obj);

此时因为声明的是GET请求没有请求体,所以obj参数就会被忽略。

在Spring Cloud环境下,Feign的Encoder*只会用来编码没有添加注解的参数*。如果你自定义了Encoder, 那么只有在编码obj参数时才会调用你的Encoder。对于Decoder, 默认会委托给SpringMVC中的MappingJackson2HttpMessageConverter类进行解码。只有当状态码不在200 ~ 300之间时ErrorDecoder才会被调用。ErrorDecoder的作用是可以根据HTTP响应信息返回一个异常,该异常可以在调用Feign接口的地方被捕获到。我们目前就通过ErrorDecoder来使Feign接口抛出业务异常以供调用者处理。

Feign的HTTP Client

Feign在默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的persistence connection 。我们可以用Apache的HTTP Client替换Feign原始的http client, 从而获取连接池、超时时间等与性能息息相关的控制能力。Spring Cloud从Brixtion.SR5版本开始支持这种替换,首先在项目中声明Apache HTTP Client和feign-httpclient依赖:

<!-- 使用Apache HttpClient替换Feign原生httpclient -->        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpclient</artifactId>        </dependency>        <dependency>            <groupId>com.netflix.feign</groupId>            <artifactId>feign-httpclient</artifactId>            <version>${feign-httpclient}</version>        </dependency>

然后在application.properties中添加:

feign.httpclient.enabled=true

总结

通过Feign, 我们能把HTTP远程调用对开发者完全透明,得到与调用本地方法一致的编码体验。这一点与阿里Dubbo中暴露远程服务的方式类似,区别在于Dubbo是基于私有二进制协议,而Feign本质上还是个HTTP客户端。如果是在用Spring Cloud Netflix搭建微服务,那么Feign无疑是最佳选择。

参考:http://blog.csdn.net/neosmith/article/details/52449921

https://springcloud.cc/spring-cloud-dalston.html#spring-cloud-feign