openfeign

1. 官方文档

2. 如何使用

2.1. 引入依赖

2.1.1. Spring Cloud 2020.0及之前版本

  • 默认Netflix Ribbon作为负载均衡器。

2.1.2. Spring Cloud 2022.0.x及之后版本

  • 从2022.0.1版本开始,Spring Cloud引入了spring-cloud-loadbalancer组件作为默认的负载均衡解决方案,以取代Netflix Ribbon。

  • 同时需要显示引入loadbalancer

<!-- loadbalancer 负载均衡器依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

        <!-- openfeign 远程调用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.2. 启动类添加注解

  • 启动类上添加@EnableFeignClients

2.3. 定义接口,添加注解@FeignClient

package org.tuling.tlmalluseropenfeigndemo.feign;

import feign.Headers;
import feign.Param;
import feign.RequestLine;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.*;
import org.tuling.tlmallcommon.Result;
import org.tuling.tlmalluseropenfeigndemo.feign.dto.OrderDTO;

//FeignConfig局部配置,让指定的微服务生效,在@FeignClient 注解中指定configuration
//@FeignClient(value = "mall-order",path = "/order",configuration = FeignConfig.class)
// tlmall-order01=服务名
@FeignClient(value = "tlmall-order01",path = "/order")
public interface OrderFeignService {


    /**
     * 根据用户id查询订单信息
     * @param userId
     * @return
     */
    @GetMapping("/getOrder")
    Result<?> getOrder(@RequestParam("userId") String userId);




    @GetMapping(value = "/post1")
    Result<?>  post1(@RequestBody OrderDTO orderDTO);


    @PostMapping("/post2")
    Result<?>  post2(@RequestBody OrderDTO orderDTO,@RequestParam("token") String token);


    @PostMapping(value = "/post3/{userId}")
    Result<?> post3(@RequestBody OrderDTO orderDTO, @PathVariable("userId") String userId);

}

3. 接口规范

3.1. 总结

和Controller那边的写法很像,可以直接拷贝

  • get请求,参数注意要加@RequestParam

3.2. 方法上和springmvc一样,必须添加@RequestMapping注解

  • @GetMapping、@PostMapping、@PutMapping等

3.3. 用@HeaderMap传递头部信息

3.4. 参数为对象问题

没法像普通controller请求样,如要直接用对象接受,必须加@RequestBody。

3.5. @RequestParam注解的坑

Feign接口的方法参数名和另一个接口的参数名一致,也要显示注明,不然会报错:.IllegalStateException: RequestParam.value() was empty on parameter 0
image

3.6. @PathVariable

注解也要显示的表明value的值为参数名,栗子:ResultData getByCode(@PathVariable(value = "accountCode") String accountCode);

3.7. post请求要用@RequestBody

两边服务的参数名要一致

  • post请求,示例
// url请求路径表单传参,body也传参
@PostMapping("/post2")
Result<?>  post2(@RequestBody OrderDTO orderDTO,@RequestParam("token") String token);

// url请求路径传参,body也传参
@PostMapping(value = "/post3/{userId}")
Result<?> post3(@RequestBody OrderDTO orderDTO, @PathVariable("userId") String userId);

3.8. 启动类注解

  • 消费者模块,启动类使用@EnableFeignClients(basePackages = "com.javadaily.feign.*"),一定要指明Feign接口的包路径,否则会报错

image

4. 配置项

4.1. http请求配置

默认使用JDK原生的http请求类,性能一般

4.1.1. 配置为Apache HttpClient5

  • 1:引入依赖
  <!-- Apache HttpClient5 -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-hc5</artifactId>
        </dependency>

  • 2:yml文件
    注意看FeignAutoConfiguration源码的逻辑
spring.cloud.openfeign.http2client.enabled=true

  • 3:FeignAutoConfiguration自动装配类的逻辑
 @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({ApacheHttp5Client.class})
    @ConditionalOnMissingBean({CloseableHttpClient.class})
    @ConditionalOnProperty(
        value = {"spring.cloud.openfeign.httpclient.hc5.enabled"},
        havingValue = "true",
        matchIfMissing = true
    )
    @Import({org.springframework.cloud.openfeign.clientconfig.HttpClient5FeignConfiguration.class})
    protected static class HttpClient5FeignConfiguration {
        protected HttpClient5FeignConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean({Client.class})
        public Client feignClient(CloseableHttpClient httpClient5) {
            return new ApacheHttp5Client(httpClient5);
        }
    }

4.1.2. 配置为OKHttp

  • 1:引入依赖
  <!-- okhttp -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>
  • 2:yml配置
# FeignAutoConfiguration中找
spring.cloud.openfeign.okhttp.enabled=true

4.2. 日志配置

4.2.1. 日志级别

  • NONE, No logging (DEFAULT).
  • BASIC(生产推荐), Log only the request method and URL and the response status code and execution time.
  • HEADERS, Log the basic information along with request and response headers,BASIC信息基础上再加请求头信息.
  • FULL, Log the headers, body, and metadata for both requests and responses.

Logger.Level.BASIC

image

Logger.Level.FULL
image

4.2.2. JavaBean方式

4.2.2.1. yml文件配置

# 固定debug
logging:
  level:
  #@FeignClient对应类所在包
    包名路径(示例:com.jf.user.feign):debug

4.2.2.2. 全局生效

// 全局生效方式
@Configuration
public class FooConfiguration {
	// feign.Logger包
	@Bean
	Logger.Level feignLoggerLevel() {
		return Logger.Level.FULL;
	}
}

4.2.2.3. 局部生效

  • @FeignClient注解指定
  • BarConfiguration类上不加@Configuration
@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class)
public interface BarClient {
	//..
}

4.2.3. yml方式

4.2.3.1. 全局生效

# 对项目所有openFeign的client都生效
spring.cloud.openfeign.client.config.default.loggerLevel: BASIC

4.2.3.2. 局部生效

# 局部生效
spring.cloud.openfeign.client.config.@FeignClient中value的值.loggerLevel: BASIC

4.3. 超时配置

4.3.1. 注意点

  • 如果同时配置了openfeign和loadbalancer,超时时间以openfeign的为准。

4.3.2. 参数说明

  • connectTimeout (连接超时)
    连接超时指的是客户端尝试与服务器建立连接(即TCP连接)的最长时间。如果在这个时间内无法建立连接,则会抛出超时异常
    英文原话:prevents blocking the caller due to the long server processing time
  • readTimeout (读取超时)
    读取超时指的是客户端从服务器读取数据的最长时间。从建立连接开始算,如果在这个时间内客户端没有从服务器接收到任何数据,则会抛出超时异常
    英文原话: is applied from the time of connection establishment and is triggered when returning the response takes too long.

4.3.3. 优先级

spring:
	cloud:
		openfeign:
			client:
				config:
          # 局部配置
          # store-server == @FeignClient中value的值
          store-server:
            # 连接超时,拨电话后5秒必须打通,嘟嘟嘟的时间【默认10s】
						connectTimeout: 5000
            # 获取响应信息超时,电话打通后,我说喂,对方5秒内必须回答【默认60s】
						readTimeout: 5000
						loggerLevel: basic
          # 全局
					default:
						connectTimeout: 5000
						readTimeout: 5000
						loggerLevel: basic

4.4. @RequestLine调用

  • 配置文件需要添加
spring:
	cloud:
		openfeign:
			client:
				config:
          contract: feign.Contract.Default
  • 使用示例
 @RequestLine("GET /getOrder?userId={id}")
 Result<?> getOrder(@Param("userId") String userId);

4.5. 压缩配置

  • FeignAcceptGzipEncodingAutoConfiguration
#开关
spring.cloud.openfeign.compression.request.enabled=true
# 压缩数据类型,之支持这3种,代码里数组mimeTypes固定的
spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
# 超过多少才压缩,单位字节
spring.cloud.openfeign.compression.request.min-request-size=2048

4.6. 编码配置

  • 支持自定义实现

4.6.1. 引入依赖

 <!-- jackson -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-jackson</artifactId>
</dependency>

  <!-- gson -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-gson</artifactId>
</dependency>

4.6.2. 指定

  • 配置类中注册bean(不推荐)
@Bean
Public Decoder decoder() {
  return new JacksonDecoder();
}

@Bean
Public Encoder encoder() {
  return new JacksonEncoder();
}

  • yml指定
openfeign:
  client:
    config:
      tlmall-order01:
        # 指定编码器
        encoder: feign.jackson.JacksonEncoder
        # 指定解码器
        decoder: feign.jackson.JacksonDecoder

4.7. 拦截器配置

  • token统一传递

4.7.1. 实现接口 RequestIntercepor

@Slf4j
public class FeignAuthRequestInterceptor implements RequestInterceptor {
    /**
     *
     * @param template 自己发给别人的请求
     */
    @Override
    public void apply(RequestTemplate template) {
        // 业务逻辑  模拟认证逻辑
        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);
        }

    }
}

4.7.2. yml添加

spring:
	cloud:
		openfeign:
			client:
				config:
					feignName:
            requestInterceptors:
							- com.example.FeignAuthRequestInterceptor

4.8. 如何动态刷新配置项的值

官方提示,不要在@FeignClient类上加@RefreshScope

spring.cloud.openfeign.client.refresh-enabled=true
  • 按官方说法,只有3个东西可以动态刷新,connectTimeout and readTimeout,url
  • feign.Request.Options as a refresh-scoped bean. This means properties such as connectTimeout and readTimeout can be refreshed against any Feign client instance.
  • A url wrapped under org.springframework.cloud.openfeign.RefreshableUrl. This means the URL of Feign client, if defined with spring.cloud.openfeign.client.config.{feignName}.url property, can be refreshed against any Feign client instance.
posted @ 2022-11-01 21:22  jf666new  阅读(55)  评论(0)    收藏  举报