仓库源文站点原文


layout: post title: "SpringCloud微服务架构之feign客户端" categories: SpringCloud tags: feign http

author: 张乘辉

Feign是一种声明式、模板化的 HTTP 客户端,在 Spring Cloud 中使用 Feign 其实就是创建一个接口类,它跟普通接口没啥两让,因此通过 Feign 调用 HTTP 请求,开发者完全感知不到这是远程方法。

整合 Feign

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
@FeignClient(value = FeignConst.COUPON_PROVIDER, url = "${feign.coupon.url:}")
public interface CouponClient {

  @GetMapping(value = "/coupon/list/page", headers = LocalsEncoder.CONTENT_TYPE_LOCALS_GET)
  RestResponse couponList(@ModelAttribute CouponCriteria criteria);

}
@EnableFeignClients(basePackages = {"com.objcoding"})
@SpringCloudApplication
public class ProviderApplication {

}

服务降级

当网络不稳定时,一个接口响应非常慢,就会一直占用这个连接资源,如果长时间不做处理,会导致系统雪崩,幸好,Feign 已经继承了熔断器 Hystrix

@FeignClient(value = FeignConst.COUPON_PROVIDER, url = "${feign.coupon.url:}", fallback = CouponClient.CouponClientFallBack.class)
public interface CouponClient {

  @GetMapping(value = "/coupon/list/page", headers = LocalsEncoder.CONTENT_TYPE_LOCALS_GET)
  RestResponse couponList(@ModelAttribute CouponCriteria criteria);

  @Component
  class CouponClientFallBack implements CouponClient {
    @Override
    public RestResponse couponList(CouponCriteria criteria) {
      return RestResponse.failed("网络超时");
    }
  }

}

拦截器

有时候微服务间的调用,需要传递权限信息,这些信息都包含在请求头了,这时我们可以通过 Feign 拦截器实现权限穿透:

@Configuration
public class WebRequestInterceptor {

  @Bean
  public RequestInterceptor headerInterceptor() {
    return template -> {
      ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      if (attributes == null) {
        return;
      }
      HttpServletRequest request = attributes.getRequest();
      Enumeration<String> headerNames = request.getHeaderNames();
      if (headerNames != null) {
        while (headerNames.hasMoreElements()) {
          String name = headerNames.nextElement();
          String values = request.getHeader(name);
          template.header(name, values);
        }
      }
    };
  }
}