Spring Cloud 七:Feign介绍与使用

一,理解Feign

1,什么是Feign

Netflix Feign

Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。

Feign实际上是对普通HTTP客户端的一层封装,其目的是降低集成成本、提升可靠性。Feign支持三种HTTP客户端,包括JDK自带的HttpURLConnection、Apache HttpClient和Square OkHttp,默认使用Apache HttpClient。

Spring Cloud Feign

Spring Cloud Feign是基于Netflix Feign实现,对Netflix Feign进行了增强,使Feign支持了Spring MVC注解,整合了Spring Cloud Ribbon和Spring Cloud Hystrix 提供负载均衡和断路器。

2,Feign和Open Feign

其实Feign和Open Feign他俩是属于同一个东西,Feign仅仅只是改名成为了Open Feign而已,然后Open Feign项目在其基础上继续发展至今。

spring-cloud-starter-feign 1.2.0.RELEASE开始 已放弃Netflix Feign而全面使用更新的Open Feign版本,

spring-cloud-starter-openfeign更是和Netflix Feign已经没有关系了。

二,Feign的使用

1,服务消费方使用

1.1,起一个eureka服务:

Spring Cloud 七:Feign介绍与使用

1.2,向eureka-server中注册一个服务提供者eureka-provider

application.yaml

spring:
  application:
    name: eureka-provider
eureka:
  client:
    service-url:
      defaultZone: http://euk-server1:7001/eureka/
  instance:
    hostname: euk-client1

HelloController.java

@RestController
public class HelloController {

    @Value("${server.port}")
    private String port;

    @GetMapping("/testFeign")
    public String testFeign() {
        System.out.println("port:" + port);
        return "服务提供者,端口为:" + port;
    }
}

Spring Cloud 七:Feign介绍与使用

1.3,使用Feign向eureka-server注册服务消费者

导入Open Feign

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

配置appliation.yml 注册到Eureka Server。

eureka:
  instance:
    hostname: localhost
  client:
    service-url:
      defaultZone: http://euk-server1:7001/eureka/
spring:
  application:
    name: eureka-consumer
server:
  port: 7008

使用@FeignClient为本应用声明一个简单的能调用的客户端,value是需要调用的服务名。

@FeignClient(value = "eureka-provider")
public interface FeignInterface {
    @RequestMapping("/testFeign")
    public String testFeign();
}

接收外部请求,通过Feign远程调用服务

@RestController
public class FeignController {
    @Autowired
    private FeignInterface feignInterface;

    @RequestMapping("/testFeign")
    public String testFeign() {
        return feignInterface.testFeign();
    }
}

在启动类上添加 @EnableFeignClients 启用 Feign

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class EurekaConsumer1Application {

    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumer1Application.class, args);
    }
}

启动eureka-consumer然后访问http://localhost:7008/testFeign 返回结果:

Spring Cloud 七:Feign介绍与使用

2,Fegin的继承特性使用

Spring Cloud Feign提供了继承特性,所谓的继承特性就是将一些公共操作提取到一个父接口中,从而继承父接口中的操作,减少代码的重复开发,节约开发成本。

  1. 编写通用服务接口A,接口方法上写@RequestMapping(),此接口用于 feign。
  2. 服务提供者 实现上面接口A。
  3. 服务消费者的feign client接口 继承A。

优点:

可以将接口的定义从 Controller 中剥离,同时配合 Maven 私有仓库就可以轻易地实现接口定义的共享,不用再复制粘贴接口进行绑定,而是实现在构建期的接口绑定,从而有效减少服务客户端的绑定配置。

缺点:

由于接口在构建期间就建立起了依赖,那么接口变动就会对项目构建造成影响,可能服务提供方修改了一个接口定义,那么会直接导致客户端工程的构建失败。

2.1:首先我们新建一个通用model,eureka-feign-api

由于我们要用到spring mvc,所以pom.xml中要依赖spring web模块

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

创建通用接口HelloInterface.java,用于eureka-provider实现,eureka-consumer继承:

@RequestMapping("/feign")
@RestController
public interface HelloInterface {
    @GetMapping("/hello")
    String hello();
}

2.2:eureka-provider依赖eureka-feign-api并实现其通用接口HelloInterface

eureka-provider的pom添加依赖eureka-feign-api

<dependency>
     <groupId>com.bobo</groupId>
     <artifactId>eureka-feign-api</artifactId>
     <version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

eureka-provider的controller实现通用接口HelloInterface

@RestController
public class FeignCommonProviderController implements HelloInterface {

    @Value("${server.port}")
    private int port;

    @Override
    public String hello() {
        return "服务提供者,我的端口为:" + port;
    }
}

eureka-provider启动类

@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaProviderApplication.class, args);
    }

}

3.3:eureka-consumer依赖eureka-feign-api并继承其通用接口HelloInterface

eureka-consumer的pom依赖添加eureka-feign-api

<dependency>
     <groupId>com.bobo</groupId>
     <artifactId>eureka-feign-api</artifactId>
     <version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

eureka-consumer继承通用接口HelloInterface

@FeignClient("eureka-provider")
public interface FeignCommonInterface extends HelloInterface {
}

eureka-consumer通过FeignCommonInterface来实现Feign的调用

@RestController
public class FeignCommonController {
    @Autowired
    private FeignCommonInterface commonInterface;

    @GetMapping("/hello")
    public String hello(){
        return commonInterface.hello();
    }
}

eureka-consumer启动类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class EurekaConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumerApplication.class, args);
    }

}

然后启动eureka-server,eureka-provider,eureka-consumer,通过服务调用eureka-consumer

http://euk-client2:7008/hello 输出:

Spring Cloud 七:Feign介绍与使用

三,Feign配置

feign的默认配置类是:org.springframework.cloud.openfeign.FeignClientsConfiguration。默认定义了feign使用的编码器,解码器等。

Feign允许自定义配置,自定义配置有如下两种方式:

  1. 一种是Java 代码配置,需要在@FeignClient(name = “eureka-consumer”,configuration = FeignAuthConfiguration.class)来引用配置。
  2. 第二种是直接配置文件配置,在application.yml或者application.properties中配置。

1,Java代码配置

public class FeignAutoConfiguration {
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("root", "root");
    }
}
@FeignClient(value = "eureka-provider",configuration = FeignAutoConfiguration.class)
public interface FeignCommonInterface extends HelloInterface {
}

如果在配置类上添加了@Configuration注解,并且该类在@ComponentScan所扫描的包中,那么该类中的配置信息就会被所有的@FeignClient共享。

最佳实践是:不指定@Configuration注解,而是手动:@FeignClient(name = “eureka-provider”,configuration = FeignAuthConfiguration.class)

2,配置文件配置

自定义拦截器:

/**
 * @author bobo
 * @date 2020-12-08
 * 自定义拦截器
 */

public class MyBasicAuthRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("Authorization", "Basic cm9vdDpyb290");
    }
}

application.yaml

spring:
  application:
    name: eureka-consumer
eureka:
  client:
    service-url:
      defaultZone: http://euk-server1:7001/eureka/
  instance:
    hostname: euk-client2
server:
  port: 7008

feign:
  client:
    config:
      eureka-peovider:
        request-interceptors:
           com.bobo.eurekaconsumer.MyBasicAuthRequestInterceptor

3,扩展

自定服务名称配置:

  feign:
     client: 
       config:  
         service-valuation: 
           connect-timeout: 5000
           read-timeout: 5000
           logger-level: full

通用配置:

  feign:
     client: 
       config:  
         default: 
           connect-timeout: 5000
           read-timeout: 5000
           logger-level: full

4,Feign压缩

Spring Cloud Feign 支持请求和响应进行GZIP压缩来提高通信效率,但是会增加CPU压力,建议把最小压缩的文档大小适度调大一点,进行gzip压缩。

 	 # 开启GZIP压缩配置:
      
      #请求GZIP压缩
      feign.compression.request.enable=true                 
      #响应GIZP压缩
      feign.compression.response.enable=true              
      #压缩支持的mime type
      feign.compression.request.mime-types=text/xml,application/xml.application/json                  
      feign.compression.request.min-request-size=1024         
      #压缩数据大小的最小值

5,Feign日志

Feign 为每一个FeignClient都提供了feign.logger实例,可在配置中或者java代码中开启日志。

feign:
  client: 
    config:  
	  # 服务名称
      eureka-provider:  
        logger-level: basic

上面logger-level有4种日志类型:

  1. none:不记录任何日志,默认值。
  2. basic:仅记录请求方法,url,响应状态码,执行时间。
  3. headers:在basic基础上,记录header信息。
  4. full:记录请求和响应的header,body,元数据。

上面的logger-level只对下面的 debug级别日志做出响应:

logging:
  level:
    com.bobo.eureka-consumer.ServiceForecast: debug

四,写在最后

上述例子代码已上传码云:https://gitee.com/songbozhao/spring-cloud-feign-test

上一篇:Java-NIO之Selector创建过程详解


下一篇:Dubbo框架学习