OpenFeign使用

OpenFeign使用

在微服务的架构中,传统的http客户端如Httpclient Okhttp HttpURLConnection RestTemplate WebClient 显然不适合。毕竟需要动态的获取服务地址,和进行负载均衡调用。

RPC框架

PC 全称是 Remote Procedure Call ,即远程过程调用,其对应的是我们的本地调用。
RPC 的目的是:让我们调用远程方法像调用本地方法一样。

具体过程就是一个服务端调用本地方法一样调用服务,rpc框架客户端会根据相应的方法的注解生成代理对象,然后代理对象中对方法名称,参数对象信息进行序列化,根据服务名称从注册中心获取需要请求的服务的地址,更据配置的协议请求对应的服务地址,服务端接收到请求之后,会根据服务名称找到对应的接口进行调用,调用完成后将结果进行序列化响应给客户端。

常用的Rpc框架有dubbo,OpenFegin,Grpc等

OpenFegin介绍

官方文档:https://docs.spring.io/spring-cloud-openfeign/docs/3.1.5/reference/html/

Feign是Netflix开发的声明式、模板化的HTTP客户端,是一款早期的rpc框架。

Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。

Spring Cloud openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Nacos,从而使得Feign的使用更加方便。

OpenFegin基础示例

1、引入依赖

我使用的springCloud版本是2021

        <!--nacos-服务注册发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--1. 添加openfeign依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        
         <!-- 客户端负载均衡 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

2、服务启动类上添加**@EnableFeignClients**

仅仅客户端添加,服务端只要能提供http接口即可

@SpringBootApplication
@Slf4j
// 用于开启Fegin客户端
@EnableFeignClients
public class OpenFeignApplication {


    public static void main(String[] args) {

        SpringApplication.run(OpenFeignApplication.class, args);
        log.info("{} startup success", "OpenfeginApplication");

    }
}

3、客服端和服务端代码示例

客户端代码示例

@RestController
@RequestMapping(value = "/feign")
public class OpenFeignController {

    @Autowired
    private FeignService feignService;


    @RequestMapping("/test")
    public String get() {
        Store stores = feignService.getStores(2L);
        feignService.delete(1L);
        Store update = feignService.update(2L, new Store());
        return "陈宫";
    }

}

@FeignClient("nacos-producer")// 此处对应的是服务名称
public interface FeignService {
    @RequestMapping(method = RequestMethod.GET, value = "/nacos-producer/stores/{storeId}")
    Store getStores(@PathVariable("storeId") Long storeId);

    @RequestMapping(method = RequestMethod.POST, value = "/nacos-producer/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);

    @RequestMapping(method = RequestMethod.DELETE, value = "/nacos-producer/stores/{storeId}")
    void delete(@PathVariable("storeId") Long storeId);
}

服务端代码示例

@RestController
@RequestMapping("/stores")
@Slf4j
public class StoreController {

    @DeleteMapping("/{storeId}")
    public void delete(@PathVariable Long storeId)  {
      log.info("删除成功");
    }
    @PostMapping("/{storeId}")
    public Store update(@PathVariable("storeId") Long storeId , @RequestBody Store store)  {
        log.info("修改成功");
        return store;
    }

    @GetMapping("/{storeId}")
    public  Store getStores2(@PathVariable Long storeId)  {
        log.info("1");
        Store store = new Store();
        return store;
    }
}

说明

客户端调用是否成功和最终的拼接的请求路径是否和服务端接口的请求路径一致,返回对象不一致也只是客户端请求成功后反序列化失败而已。

配置优先级

@EnableFeignClients可以指定全局的配置类,或者@Configuration注解下被扫描到的Feign的配置都是全局配置

@EnableFeignClients(basePackages = {"cn.sry1201.*","cn.sry"},defaultConfiguration = FeignConfig.class)

局部的注解配置类

@FeignClient(name = "nacos-producer2",configuration = FeignConfig.class)// 可以指定配置类,配置类中进行一些配置

还有全局配置文件和局部的配置文件

默认的优先级是 局部文件配置>全局默认文件配置>局部注解配置>全局默认注解配置

@FeignClient属性

不通过注册中心调用接口

如果引入了注册中心依赖,以我这个版本为例,接口请求路径中的ip和端口都是服务名,最终客户端负载均衡器会从注册中心获取对一个服务名的ip地址,然后替换成实际ip进行访问

我们也可以直接通过ip地址访问,示例如下,将基础示例中的配置改成如下进行测试即可

@FeignClient(name = "nacos-producer2",url = "http://localhost:8004")

动态设置@FeignClient属性

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
    //..
}

配置类

@FeignClient(name = "nacos-producer2",configuration = FeignConfig.class)// 可以指定配置类,配置类中进行一些配置

配置类分全局配置和局部配置,如果加了@Configuration注解那就是全局配置

feign.Logger

日志级别

这里的logger是feign.Logger

public class FeignConfig {

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

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

  • NONE【性能最佳,适用于生产】:不记录任何日志(默认值)。
  • BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。
  • HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
  • FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。

当然上述级别说的是在springboot打印debug级别日志的情况下,feign定义的日志级别来打印不同完整度的日志,所以需要指定@FeignClient所在类的日志级别为debug,似乎不需要到日志的配置文件中操作,外部指定对应的记录器日志级别同样生效

logging:
  # 指定日志配置文件位置,指定之后,外部配置文件失效,但是可以被配置文件内部引用,注意logback-spring.xml这个名称不能修改
  config: classpath:log/logback-spring.xml
  level:
    #指定根记录器的级别,
    root: debug
    # 单独指定某个记录器的日志级别
    cn.sry1201.producer.service: debug

以下是FULL级别的日志

支持Feign原生的注解

Spring Cloud 在 Feign 的基础上做了扩展,使用 Spring MVC 的注解来完成Feign的功能。原生的 Feign 是不支持 Spring MVC 注解的,如果你想在 Spring Cloud 中使用原生的注解方式来定义客户端也是可以的,通过配置契约来改变这个配置,Spring Cloud 中默认的是 SpringMvcContract。

1、配置类中添加配置

    /**
     * 修改契约配置,支持Feign原生的注解
     * @return
    @Bean
    public Contract feignContract() {
        return new Contract.Default();
    }

2、使用feign原生注解示例

@FeignClient(value = "mall-order",path = "/order")
public interface OrderFeignService {
    @RequestLine("GET /findOrderByUserId/{userId}")
    public R findOrderByUserId(@Param("userId") Integer userId);
}
超时时间配置

配置类中添加配置

// 分别是连接超时时间和读取超时时间
@Bean
public Request.Options options() {
return new Request.Options(5000, 10000);
}

自定义请求拦截器
public class FeignAuthRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // 业务逻辑
        String access_token = UUID.randomUUID().toString();
        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();
    }
}

配置文件

局部配置类中局部配置在配置文件中的实现

# feign日志局部配置
feign:
  client:
    config:
      nacos-producer:
        loggerLevel: BASIC
#        contract: feign.Contract.Default #设置为默认的契约  (还原成原生注解)
        # 连接超时时间,默认2s
        connectTimeout: 5000
        # 请求处理超时时间,默认5s
        readTimeout: 10000
        request-interceptors:
          - cn.sry1201.producer.intercepter.feign.CustomFeignInterceptor

配置优先级验证

添加配置和配置类的情况下,打印日志如下,显然是配置文件中配置优先级高

客户端组件配置

Feign 中默认使用 JDK 原生的 URLConnection 发送 HTTP 请求,我们可以集成别的组件来替换掉 URLConnection,比如 Apache HttpClient,OkHttp。

feign:
  #feign 使用 okhttp
  httpclient:
    enabled: false
  okhttp:
    enabled: true#### 配置Apache HttpClient

开启配置后引入相关依赖即可,总之我这里报错了,不管,这个就做个记录吧,知道有这个配置

PoolingHttpClientConnectionManager : Closing expired connections

GZIP 压缩配置(不建议,会导致传输过程出现数据错误等…)

仅做记录,未测试

官方文档:https://docs.spring.io/spring-cloud-openfeign/docs/3.1.5/reference/html/#feign-requestresponse-compression

开启压缩可以有效节约网络资源,提升接口性能,我们可以配置 GZIP 来压缩数据:

feign:
  # 配置 GZIP 来压缩数据
  compression:
    request:
      enabled: true
      # 配置压缩的类型
      mime-types: text/xml,application/xml,application/json
      # 最小压缩值
      min-request-size: 2048
    response:
      enabled: true

注意:只有当 Feign 的 Http Client 不是 okhttp3 的时候,压缩才会生效,配置源码在FeignAcceptGzipEncodingAutoConfiguration

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

注意事项

1、需要注意的是FeignClient的name属性不可重复

关联信息

  • 关联的主题:
  • 上一篇:
  • 下一篇:
  • image: 20221021/1
  • 转载自:
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenFeign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加容易。通过使用OpenFeign,我们可以定义一个接口用于调用远程Web服务,然后在运行时生成一个实现该接口的代理类。 以下是使用OpenFeign的步骤: 1. 添加依赖 在Maven项目中,我们需要添加以下依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ``` 2. 创建Feign客户端接口 定义一个接口,用于调用远程Web服务。该接口通常会使用Spring MVC注解来定义请求路径、请求参数等信息。 ```java @FeignClient(name = "service-name") public interface MyFeignClient { @RequestMapping(value = "/api/resource", method = RequestMethod.GET) Resource getResource(@RequestParam("id") Long id); } ``` 其中,@FeignClient注解用于定义Feign客户端的名称,name属性指定了远程服务的名称。@RequestMapping注解则用于定义请求路径和请求方法。 3. 注入Feign客户端 在需要调用远程服务的地方,我们可以通过@Autowired注解来注入Feign客户端。 ```java @RestController public class MyController { @Autowired private MyFeignClient myFeignClient; @GetMapping("/resource/{id}") public Resource getResource(@PathVariable Long id) { return myFeignClient.getResource(id); } } ``` 这里,我们将Feign客户端注入到了控制器中,在控制器中调用了getResource方法。 4. 配置Feign客户端 我们可以通过配置文件来配置Feign客户端的行为。例如,我们可以配置连接超时时间、读取超时时间等。 ```yaml feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 ``` 这里,我们将连接超时时间和读取超时时间都设置为了5秒。 以上就是使用OpenFeign的基本步骤,它使得调用远程Web服务变得更加容易。同时,OpenFeign还提供了很多高级特性,例如请求拦截器、响应拦截器等,可以帮助我们更好地管理Web服务客户端。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值