微服务架构精粹:深入探索OpenFeign的核心机制

关注微信公众号 “程序员小胖” 每日技术干货,第一时间送达!

引言

在微服务架构的世界里,服务间的顺畅通信至关重要。OpenFeign,作为Spring Cloud生态系统中的一颗璀璨明珠,以其声明式的HTTP客户端特性,极大地简化了微服务间的交互。本文将带您深入探索OpenFeign的核心原理,并结合实际案例,剖析其在日常开发中的应用场景,助力您在微服务通信中更加得心应手。

OpenFeign简介

OpenFeign 的中心思想在于通过提供一种声明式、注解驱动的接口化服务调用方式,极大地简化了微服务架构中的RESTful API调用以及服务间通信的复杂性。它使得开发者可以聚焦于业务逻辑本身,如同调用本地方法一样便捷地调用远程服务,而不必深陷于HTTP请求细节的实现。OpenFeign 动态生成代理类来处理请求和响应转换,有效地降低了耦合度,并且它集成了Spring Cloud生态系统,支持服务发现、负载均衡、容错处理等高级功能,从而增强了微服务间的通信效率与稳定性,对微服务架构的整体优化起到了重要作用。

工作流程

核心特性

在看了解每一个核心特性之前,有两个固定的前置条件,后面不在单独赘述。

  1. 引入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 在启动类上添加@EnableFeignClients注解,开启openFeign功能

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

声明式客户端:

OpenFeign允许开发者通过定义接口并添加注解的方式来创建HTTP客户端。这种方式使得编写的客户端代码更加简洁、直观,并且易于维护。
Java 代码示例

定义一个Feign客户端接口,并使用@FeignClient注解标记

@FeignClient(value = "user-center", path = "/admin/feign/serviceProvider")
public interface ServiceProviderClient {

    @GetMapping("/service/path")
    String getServiceData();

    @PostMapping("/service/path")
    String createServiceData(@RequestBody SomeRequestObject data);

    @PutMapping("/service/path/{id}")
    String updateServiceData(@PathVariable("id") Long id, @RequestBody SomeRequestObject data);

    @DeleteMapping("/service/path/{id}")
    String deleteServiceData(@PathVariable("id") Long id);
}

Spring Cloud集成:

OpenFeign与Spring Cloud紧密集成,支持Spring MVC的注解,如@RequestMapping,并利用Spring的HttpMessageConverters来处理请求和响应的编解码。

  1. 编写OpenFeign客户端
@Api(tags = "用户中心Feign-Api")
@FeignClient(value = "user-center", path = "/userInfo")
public interface UserFeignApi {

    @ApiOperation("根据用户ID查询用户信息")
    @GetMapping("/getUserInfoById")
    List<UserInfoDTO> getUserInfoById(@RequestParam("userId") Long userId);
}
  1. 微服务调用者发起调用,像调用本地方式一样调用远程微服务提供者

@Api(tags = {"用户Feign-Api"})
@RestController
@RequestMapping("/admin/feign/userInfo")
public class BackendUserFeignController {

    @Autowired
    private UserFeignApi userApi;

    @ApiOperation("根据用户ID查询用户详情")
    @GetMapping("/getUserInfoById")
    public BaseResult<List<UserInfoDTO>> getUserInfoById(@RequestParam("userId") Long userId) {
        return userApi.getUserInfoById(userId);
    }
}

负载均衡:

OpenFeign集成了Ribbon,一个客户端负载均衡器,使得通过OpenFeign发起的HTTP请求可以自动地在多个服务实例间进行负载均衡。如果想要自定义负载均衡策略,还需要做点事情。

  1. 引入ribbon依赖
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
  1. LoadBalancer默认采用了轮询的负载均衡策略,如果你想自定义负载均衡策略,可以在application.yml或application.properties配置文件中增加如下的配置
spring:
  cloud:
    loadbalancer:
      ribbon:
        enabled: true
        nfloadbalancer:
          rule:
            # 随机 
            name: com.netflix.loadbalancer.RandomRule
            # 加权响应时间
            name: com.netflix.loadbalancer.WeightedResponseTimeRule
            # 区域避免
            name: com.netflix.loadbalancer.AvailabilityFilteringRule
            # 自定义策略 若要实现自定义策略,需要创建一个类实现com.netflix.loadbalancer.IRule接口,并在配置中指定这个自定义类的全限定名

容错和熔断:

OpenFeign可以与Hystrix结合使用,提供容错和熔断机制。这有助于防止服务故障的蔓延,提高系统的稳定性和可靠性。

日志增强:

OpenFeign提供了日志增强功能,允许开发者通过配置不同的日志级别来监控HTTP请求和响应的详细信息。日志级别包括NONE(无日志)、BASIC(基本信息)、HEADERS(请求和响应头信息)和FULL(完整的请求和响应信息)。

  1. Java Bean配置方式
    利用@Configuration实现全局生效,对所有的微服务调用者都生效
    定义一个配置类,指定日志级别
// 注意: 此处配置@Configuration注解就会全局生效,如果想指定对应微服务生效,就不能配置
@Configuration
@Configuration
public class FeignConfig {
    
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

通过源码可以看到日志等级有4种,分别是:

  • NONE【性能最佳,默认值】:不记录任何日志。
  • BASIC【适用于生产环境追踪问题】: 仅记录请求方法、URL、响应状态代码以 及执行时间。
  • HEADERS:记录BASIC级别的基础上, 记录请求和响应的header。
  • FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。
  1. 在application.yml配置文件中配置 Client 的日志级别才能正常输出日志,格式
    是"logging.level.feign接口包路径=debug"
logging: 
  level: 
  com.tuling.mall.feigndemo.feign: debug
  1. 全局生效,对所有的微服务调用者都生效
spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            loggerLevel: FULL
  1. 局部生效,yml中对调用的微服务提供者进行配置
    对应属性配置类:org.springframework.cloud.openfeign.FeignClientProperties.FeignClientConfiguration
spring:
  cloud:
    openfeign:
      client:
        config:
          mall-order: #对应微服务
            loggerLevel: FULL

支持多种HTTP客户端:

除了内置的HTTP客户端,OpenFeign还允许开发者通过添加相应的依赖和配置来使用Apache HttpClient或OkHttp等第三方HTTP客户端。
Feign发起调用真正执行逻辑:feign.Client#execute (扩展点)


@Override
public Response execute(Request request, Options options) throws IOException{
  HttpURLConnection connection = convertAndSet(request, options);
  return convertResponse(connection, request);
}
  1. 配置Apache HttpClient5
  • 引入依赖
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-hc5</artifactId>
</dependency>
  • 修改yaml配置,启用Apache HttpClient5
spring:
  cloud:
    openfeign:
      #feign client使用 Apache HttpClient5
      httpclient: 
        hc5:
          enabled: true

关于配置可参考源码: org.springframework.cloud.openfeign.FeignAutoConfiguration


测试:调用会进入feign.httpclient.ApacheHttpClient#execute
2. 配置OkHttp

  • 引入依赖
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>
  • 修改yaml配置,启用Apache HttpClient5
spring:
  cloud:
    openfeign:
      #feign client使用 Apache okhttp
      httpclient: 
        okhttp:
          enabled: true

关于配置可参考源码: org.springframework.cloud.openfeign.FeignAutoConfiguration

测试:调用会进入feign.okhttp.OkHttpClient#execute

请求和响应压缩:

OpenFeign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。

spring:
  cloud:
    openfeign:
      compression: # 配置 GZIP 来压缩数据
        request:
          enabled: true 
          mime-types: text/xml,application/xml,application/json 
          min-request-size: 1024 # 最小请求压缩阈值
        response:
        enabled: true

注意:当 Feign 的 HttpClient不是 okHttp的时候,压缩配置不会生效,配置源码在
FeignAcceptGzipEncodingAutoConfiguration

核心代码就是 @ConditionalOnMissingBean(type=“okhttp3.OkHttpClient”),表示 Spring容器
中不包含指定的 bean 时条件匹配,也就是没有启用 okhttp3 时才会进行压缩配置。

拦截器配置

通常我们调用的接口都是有权限控制的,很多时候可能认证的值是通过参数去传递的,还有就是通过
请求头去传递认证信息,比如 Basic 认证方式。
Feign 中我们可以直接配置 Basic 认证

@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
    retuen new BasicAuthRequestInterceptor"admin","123456";
}
  • 使用场景

    统一添加 header 信息;

    对 body 中的信息做修改或替换;

  • 扩展点: feign.RequestInterceptor
    每次feign发起http调用之前会去执行拦截器中的逻辑。所以,如果想要在发送请求时增加一些额外请求参数的话,可以继承这个接口,原因是因为openFeign在远程调用之前会遍历容器中的RequestInterceptor,调用RequestInterceptor的apply方法,创建一个新的Request进行远程服务调用。通过过实现RequestInterceptor给容器中添加自定义的RequestInterceptor实现类,在这个类里面设置需要发送请求时的参数。

public interface RequestInterceptor {

  /**
   * Called for every request. Add data using methods on the supplied {@linkRequestTemplate}.
   */
  void apply(RequestTemplate template);
}

自定义的RequestInterceptor实现类

@Slf4j
public class FeignAuthRequestInterceptor implements RequestInterceptor {
  @Override
  public void apply(RequestTemplate template) {
  // 业务逻辑 模拟认证逻辑测试也可以在yml中配置
  ServletRequestAttributes attributes = (ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
  if(null != attributes){
      HttpServletRequest request = attributes.getRequest();
      String access_token = request.getHeader("Authorization");
      log.info("从Request中解析请求头:{}",access_token);
      //设置token
      template.header("Authorization",access_token);
     }
    }
  }

  @Configuration // 全局生效
  public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
      return Logger.Level.FULL;
    }
    
  /**
    * 自定义拦截器
    * @return
  */
    @Bean
    public FeignAuthRequestInterceptor feignAuthRequestInterceptor(){
    return new FeignAuthRequestInterceptor();
  }
}

也可以在yaml中配置

spring:
  cloud:
    openfeign:
      client:
        config:
          user-center: #对应微服务
            requestInterceptors: #配置拦截器
              -
                com.user.feigndemo.interceptor.AuthRequestInterceptor

user-center端可以通过 @RequestHeader获取请求参数进行校验,可以在filter或者mvc interceptor
中进行处理

#结语

OpenFeign通过简化服务间通信的复杂性,实现了微服务之间的透明和高效协同。通过注解和自动配置,开发者能够轻松定义服务接口,而Feign在后台处理请求的发送和响应的接收。集成服务发现和负载均衡机制,Feign不仅提高了调用的灵活性,也增强了系统的健壮性。这使得微服务架构下的接口调用更加简洁、高效,为构建现代化的分布式应用提供了有力支撑。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值