zoukankan      html  css  js  c++  java
  • Spring Cloud微服务调用Feign初探

    1、技术概述

    Spring Cloud Feign是声明式、模块化的Http客户端,可以快捷优雅的调用HTTP接口。由于用到了需要调用其他的微服务,因此需要通过HTTP方式进行调用。之前试过了RestTemplate,感觉用起来不太方便,因此选择了Fegin。这次技术难点主要涉及到接口如何声明、以及在调用过程如何传递Cookies,设置Header。

    2、技术详述

    这是Feign的Github地址:https://github.com/OpenFeign/feign

    ​ 这里已经假设你的Spring Boot项目拥有了一个Eureka注册中心,多个微服务的客户端,同时你已经明白他们之间的工作流程。这个不是本篇重点,因为使用Eureka进行服务注册和发现在网上已经有很多资料。这里使用到了Maven,并且假设你已经知道如何使用Maven。

    使用Feign步骤如下:

    1.导入依赖

    2.添加注解@EnableFeignClients

    3.声明Feign客户端接口

    4.使用第3步声明的接口

    接着我们一步步来使用Feign。

    1. 导入依赖(这里使用Maven进行依赖管理)

      在你的pom.xml文件中,添加如下依赖:

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

      你要注意的是Spring Cloud版本和Spring Boot 之间对应关系(这里以Spring Boot 2.3.0.RELEASE为例,因此Spring Cloud对应版本应该为Hoxton.SR5,有关Spring Cloud版本和Spring Boot 之间对应关系可以参见:https://start.spring.io/actuator/info或者通过https://start.spring.io/自动生成Spring Boot项目而不必关心他们之间的对应关系),这里列出部分pom.xml有关Spring Cloud示例:

       ...
       <parent>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-parent</artifactId>
           <version>2.3.0.RELEASE</version>
           <relativePath/> <!-- lookup parent from repository -->
       </parent>
      ...
      <properties>
          ...
          <spring-cloud.version>Hoxton.SR5</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>
      </dependencyManagement>
      
    2. 添加注解@EnableFeignClients

      ​ 在你的服务消费者的启动类或者配置类上添加@EnableFeignClients注解以启用Feign。

      @SpringBootApplication
      @EnableEurekaClient
      @EnableDiscoveryClient
      @EnableFeignClients
      public class NotificationCenterApplication {
          public static void main(String[] args) {
              SpringApplication.run(NotificationCenterApplication.class, args);
          }
      }
      

      相信你应该知道这些是有关Eureka客户端相关注解:

      @EnableEurekaClient
      @EnableDiscoveryClient
      
    3. 声明Feign客户端接口

      假设我们需要调用某个服务提供者的接口,因此我们先来到服务提供提供者相应的接口代码。我们声明Feign客户端接口将以它为蓝图。

      @PostMapping("/todos")
      @ResponseBody
      public Object addTodo(@RequestBody @Valid TodoAddResource resource) {
      	//...
      }
      

      接者在我们服务消费者这里声明Feign客户端接口,它看起来是这样的:

      @FeignClient(name = "TODO-SERVICE")
      public interface TodoRemoteService {
          @PostMapping("/todos")
          Object addTodo(@RequestBody TodoAddResource resource);
      }
      

      声明Feign客户端接口非常简单,你只需要声明一个接口,把需要服务提供者的接口方法签名在接口中描述出来。注意:

      1. @PostMapping("/todos")是必须的,它规定接口调用的路径和请求方法。

      2. @RequestBody是必须的,它规定参数如何传递。

      3. @FeignClient(name = "TODO-SERVICE")是必须的,它提供要调用的相应服务信息以及配置,其中name表示服务提供者的标识,你可以在Eureka注册中心看到。

      4. 方法返回值为Object与原方法相同,这里会涉及到相应的转换器。如果设置为String那么返回是原接口返回内容字符串形式。

      5. 方法名addTodo不必相同,因为以上信息足以确定调用目标方法。

    4. 使用第3步声明的接口

      最后一步,在你需要调用远程微服务地方注入刚才我们声明的Feign客户端接口:

      @Autowired
      TodoRemoteService todoService;
      
      public void foo() {
      	//...
          TodoAddResource resource = new TodoAddResource();
          todoService.addTodo(resource);
      }
      

    3、技术使用中遇到的问题和解决过程

    在调试远程微服务调用过程中,发现出现了调用超时异常。

    可能是连接超时或者调用方法执行时间超时,可以在application.yml这样配置(连接超时ConnectTimeout和读超时ReadTimeout单位均为毫秒ms):

    feign:
      client:
        config:
          default:
            connectTimeout: 10000
            readTimeout: 600000
    

    ​ 这是默认全局配置,也可以根据相应调用的服务进行配置,更多信息可以参考文末的链接:Feign超时配置。配置的时间设置可以结合业务需求,同时使用Hystrix 熔断器进行相应处理。

    在调用远程服务中,如何将原来请求中Cookies信息转发到调用请求,或者设置Header?

    在使用@FeignClient注解中,其实我们还有一个configuration属性没有用到,这里可以指定相应Feign客户端配置。我们可以配置一个拦截器,把原来请求中信息复制到调用远程服务的请求上,这里我们转发相应的Cookies和设置一个X-XSRF-TOKEN请求头信息,这个X-XSRF-TOKEN的值从原本Cookies中一个名为XSRF-TOKEN的Cookie获取。

    我们首先可以新建一个类:

    public class FeignAuthRequestInterceptor implements RequestInterceptor {
        private static final String XSRF_TOKEN_HEADER_NAME = "X-XSRF-TOKEN";
        private static final String XSRF_TOKEN_COOKIE_NAME = "XSRF-TOKEN";
        private static final String COOKIE_HEADER_NAME = "Cookie";
        private final Logger logger = LoggerFactory.getLogger(FeignAuthRequestInterceptor.class);
    
        @Override
        public void apply(RequestTemplate requestTemplate) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            Cookie[] cks = request.getCookies();
            if (cks.length > 0) {
                List<String> cookies = new ArrayList<>(cks.length);
                for (int i = 0; i < cks.length; i++) {
                    cookies.add(cks[i].getName() + "=" + cks[i].getValue());
                    logger.info("cookie found:{}", cks[i].getName());
                    if (XSRF_TOKEN_COOKIE_NAME.equals(cks[i].getName())) {
                        requestTemplate.header(XSRF_TOKEN_HEADER_NAME, cks[i].getValue());
                    }
                }
                requestTemplate.header(COOKIE_HEADER_NAME, cookies);
            }
        }
    }
    

    之后,在需要转发原来请求信息的Feign客户端接口上,使用@FeignClient注解的configuration属性指定改配置类即可(配置类还可以配置Feign客户端的Encoder、Decoder等):

    @FeignClient(value = "TODO-SERVICE", configuration = FeignAuthRequestInterceptor.class)
    public interface TodoRemoteService {
        @PostMapping("/todos")
        String addTodo(@RequestBody TodoAddResource resource);
    }
    

    4、进行总结

    ​ 总的来说Feign使用起来较为简洁,同时也支持强大的机制支撑。这里提供博客只是较为简单介绍和使用Feign部分功能,同时列举一些常见问题的解决方案,更多关于Feign还需要自行查找相关资料,由于自己对于Feign了解不是很充分,错误在所难免,还望大家多多指教。学无止境,多实践才能加深印象。

    5、参考文献、参考博客

    标题 作者 链接
    Feign接口方法返回值设置 CoderYin https://blog.csdn.net/CoderYin/article/details/90754547
    Spring Cloud 进阶之路 -- Feign 的使用 老麻在此 https://blog.csdn.net/antma/article/details/81317707
    SpringBoot和SpringCloud对应的关系 代码拯救不了世界 https://www.cnblogs.com/kaifaxiaoliu/p/11980114.html
    Feign超时配置 妙蛙大种子 https://blog.csdn.net/zhang7495826/article/details/96002377
  • 相关阅读:
    js 数据类型的转换
    js数组学习方法汇总
    跳转页面的方法总结
    今天用js做拉一个时钟
    今天用js做拉一个时钟
    js中字符的比较
    1005 继续(3n+1)猜想 (25分)
    1002 写出这个数
    日期差值
    1040 有几个PAT (25分)
  • 原文地址:https://www.cnblogs.com/Zhifeng-Shen/p/13130466.html
Copyright © 2011-2022 走看看