Spring Cloud OpenFeign基础入门

OpenFeign是什么

Feign是一个声明式的Web Service客户端,是一种声明式、模板化的HTTP客户端。而OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。

  1. 可插拔的注解支持,包括Feign注解和JSX-RS注解
  2. 支持可插拔的HTTP编码器和解码器
  3. 支持Hystrix和它的Fallback
  4. 支持Ribbon的负载均衡
  5. 支持HTTP请求和响应的压缩。

OpenFeign入门

创建父Pom工程:cloud-openfeign-practice

此工程用于存放所有关于openfeign的示例。

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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.msr.better</groupId>
    <artifactId>cloud-openfeign-practice</artifactId>
    <version>1.0</version>

    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.3.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>Hoxton.SR3</spring.cloud-version>
    </properties>
    <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>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

创建模块:cloud-openfeign-hehllo

pom.xml

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

配置文件

application.xml

server:
  port: 8010
spring:
  application:
    name: openfeign-hello
# 日志
logging:
  level:
    com.msr.better.feign.service.HelloFeignService: debug

配置类

@Configuration
public class HelloFeignServiceConfig {

    /**
     * Logger.Level 的具体级别如下:
     * NONE:不记录任何信息
     * BASIC:仅记录请求方法、URL以及响应状态码和执行时间
     * HEADERS:除了记录 BASIC级别的信息外,还会记录请求和响应的头信息
     * FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

serivce

@FeignClient(name = "github-client", url = "https://api.github.com", configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService {

    /**
     * content:
     * {
     *  "message":"Validation Failed",
     *  "errors":[{"resource":"Search","field":"q","code":"missing"}],
     *  "documentation_url":"https://developer.github.com/v3/search"
     *  }
     *
     * @param queryStr
     * @return
     */
    @GetMapping(value = "/search/repositories")
    String searchRepo(@RequestParam("q") String queryStr);

}

在上面的HelloFeignService中通过@FeignClient注解手动指定了该接口要访问的URL(https://api.github.com),调用searchGithubRepoByStr方法时,最终会发起GET请求https://api.github.com/search/repositories?q=输入的参数。

controller

@RestController
public class HelloFeignController {

    @Autowired
    private HelloFeignService helloFeignService;

    @GetMapping(value = "/search/github")
    public String searchGithubRepoByStr(@RequestParam("searchStr") String searchStr) {
        return helloFeignService.searchRepo(searchStr);
    }
}

启动类

@SpringBootApplication
@EnableFeignClients
public class OpenFeignHelloApplication {

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

@EnableFeignClients包扫描时,扫描所有@FeignClient。

启动测试

运行启动类之后,在浏览器或者PostMan之类的工具访问http://localhost:8010/search/github?searchStr=spring-cloud

OpenFeign工作原理

  • 添加@EnableFeignClients注解开启对@FeignClient注解的扫描加载处理。根据Feign Client的开发规范,定义接口并添加@FeiginClient注解
  • 当程序启动之后,会进行包扫描,扫描所有@FeignClient注解的接口,并将这些信息注入到IOC容器中。当定义的Feign接口被调用时,通过JDK的代理的方式生成具体的RequestTemplate。Feign会为每个接口方法创建一个RequestTemplate对象。该对象封装了HTTP请求需要的所有信息,例如请求参数名、请求方法等信息。
  • 然后由RequestTemplate生成Request,把Request交给Client去处理,这里的Client可以是JDK原生的URLConnection、HttpClient或Okhttp。最后Client被封装到LoadBalanceClient类,看这个类的名字既可以知道是结合Ribbon负载均衡发起服务之间的调用,因为在OpenFeign中默认是已经整合了Ribbon了。

OpenFiegn的基础功能

剖析@FeignClient注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {...}

从FeignClient的注解可以看得出,ElementType.TYPE说明FeignClient的作用目标是接口。其常用的属性如下:

  • name:执行FeignClient的名称,如果项目中使用Ribbon,name属性会作为微服务的名称,用作服务发现。
  • url:url一般用于调试,可以手动指定@FeignClient调用的地址
  • decode404:当发生404错误时,如果该字段为true,会调用decoder进行解码,否则抛出FeignException。
  • configuration:Feigin配置类,可自定义Feign的Encode,Decode,LogLevel,Contract。
  • fallback:定义容错的类,当远程调用的接口失败或者超时的时候,会调用对应接口的容错罗杰,fallback执行的类必须实现@FeignClient标记的接口。在OpenFeign的依赖中可以发现,集成Hystrix。
  • fallbackFactory:工厂类,用于生成fallback类实例,通过此属性可以实现每个接口通用的容错逻辑,以达到减少重复的代码。
  • path:定义当前FeignClient的统一前缀。

OpenFeign开始GZIP压缩

OpenFeign支持对请求和响应进行GZIP压缩,以此来提供通信效率。只需在配置文件中配置即可,比较简单。

server:
  port: 8011
spring:
  application:
    name: openfeign-gzip
logging:
  level:
    com.msr.better.feign.service.HelloFeignService: debug
feign:
  # 压缩配置
  compression:
    request:
      enabled: true
      # 配置压缩支持的MIME TYPE
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048  # 配置压缩数据大小的下限
    response:
      enabled: true # 配置响应GZIP压缩

等价的properties配置

feign.compression.request.enabled=true
# 配置压缩支持的MIME TYPE
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 配置压缩数据大小的下限
feign.compression.request.min-request-size=2048
# 配置响应GZIP压缩
feign.compression.response.enabled=true

支持属性文件配置

对单个特定名称的FeignClient进行配置

@FeignClientde的配置信息可以通过配置文件的方式来配置

server:
  port: 8011
spring:
  application:
    name: openfeign-gzip
logging:
  level:
    com.msr.better.feign.service.HelloFeignService: debug
feign:
  # 压缩配置
  compression:
    request:
      enabled: true
      # 配置压缩支持的MIME TYPE
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048  # 配置压缩数据大小的下限
    response:
      enabled: true # 配置响应GZIP压缩
  client:
    config:
      # 需要配置的FeignName
      github-client:
        # 连接超时时间
        connectTimout: 5000
        # 读超时时间
        readTimeut: 5000
        # Feign的日志级别
        loggerLevel: full
        # Feign的错误解码器
        errorDecode: com.example.SimpleErrorDecoder
        # 设置重试
        retryer: com.example.SimpleRetryer
        # 拦截前
        requestInterceptors:
          - com.example.FirstInterceptor
          - com.example.SecondInterceptor
        decode404: false
        # Feign的编码器
        encoder: com.example.SimpleEncoder
        # Feign的解码器
        decoder: com.example.SimpleDecoder
        # Feign的contract配置
        contract: com.example.SimpleContract

作用于所有FeignClient的配置

在@EnableFeignClients注解上有一个defaultConfiguration属性,可以将默认设置写成一个配置类,例如这个类叫做DefaultFeignClientConfiguration。

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignClientConfiguration.class)
public class FeignClientConfigApplication{
    SpringApplication.run(FeignClientConfigApplication.class, args);
}

同时也可以在配置文件中配置

feign:
  client:
    config:
      default:
        # 连接超时时间
        connectTimout: 5000
        # 读超时时间
        readTimeut: 5000
        # Feign的日志级别
        loggerLevel: full
        ...

但是如果以上两种方式(在配置文件和在注解中配置FeignClient的全局配置),最后配置文件会覆盖注解上执行配置类的方式。但是可以在配置文件中添加feign.client.default-to-properties=false来改变Feigin配置的优先级。

FeignClient开启日志

其实在上面的就已经是配置了FeignClient的日志了。Feign为每一个Feign都提供了一个fegin.Logger实例。可以在配置中开启日志输出,开启的步骤也很简单。

第一步:在配置文件中配置日志输出

logging:
  level:
    # 指定那个FeignClient接口的请求需要输出日志,以及日志级别
    com.msr.better.feign.service.HelloFeignService: debug

第二步:通过Java代码的方式在主程序入口配置日志Bean


    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

又或者通过配置类配置,并在@FeignClient注解中执行改配置类。

@Configuration
public class HelloFeignServiceConfig {

    /**
     * Logger.Level 的具体级别如下:
     * NONE:不记录任何信息
     * BASIC:仅记录请求方法、URL以及响应状态码和执行时间
     * HEADERS:除了记录 BASIC级别的信息外,还会记录请求和响应的头信息
     * FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

FeignClient超时配置

Feign的调用分为两层,Ribbon的调用和Hystrix的调用。但是高版本的Hystrix默认是关闭的。一般出现想这样的异常:Read timed out executing POST http://***,是由Ribbon引起,这样可以适当得调大一下Ribbon的超时时间

ribbon:
  ConnectTimeout: 2000
  ReadTimeout: 5000

HystrixRuntimeException: XXX timed -out and no fallback available .这就是Hystrix的超时报错

feign:
  hystrix:
    enabled: true
# 设置hystrix超时时间
hystrix:
  shareSecurityContext: true
  command:
    default:
      circuitBreaker:
        sleepWindowinMilliseconds: 10000
        forceClosed: true
      execution:
        isolation:
          thread:
            timeoutinMilliseconds: 10000

最后

可关注我的微信公众号
在这里插入图片描述

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值