Feign

1.Feign是什么

Feign 是 Netflix 公司开发的一个声明式的 REST 调用客户端
(调用远程的restful风格的http接口 的一个组件)
调用组件其实很多,比如:
1、Httpclient(apache)
2、Httpurlconnection (jdk)
3、restTemplate(spring)
4、OkHttp(android)
5、Feign (Netflix) --> 实现非常优雅
Spring Cloud Feign 对 Ribbon 负载均衡进行了简化,在其基础上进行了进一步的封装,在配置上大大简化了开发工作,它是一种声明式的调用方式,它的使用方法是定义一个接口,然后在接口上添加注解,使其支持了Spring MVC标准注解和HttpMessageConverters,Feign可以与Eureka和Ribbon组合使用以支持负载均衡

2.Feign能干什么?

Feign旨在简化微服务消费方(调用者,客户端)代码的开发,前面在使用Ribbon+RestTemplate进行服务调用时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方式,但是在实际开发中,由于服务提供者提供的接口非常多,一个接口也可能会被多处调用,Feign在Ribbon+RestTemplate的基础上做了进一步封装,在Feign封装之后,我们只需创建一个接口并使用注解的方式来配置,即可完成对服务提供方的接口绑定,简化了使用Ribbon + RestTemplate的调用,自动封装服务调用客户端,减少代码开发量

3.Feign的使用

3.1添加依赖

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

3.2配置Feign

从SpringCloudEdgware开始,Feign支持使用属性自定义Feign。对于一个指定名称的FeignClient(例如该FeignClient的名称为feignName),Feign支持如下配置项

feign:
  compression: #支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能
    request:
      enabled: true #开启请求压缩
      mime-types: text/xml,application/xml,application/json #开启支持压缩的MIME TYPE
      min-request-size: 2048 #配置压缩数据大小的下限
    response:
      enabled: true #开启相应压缩
  client:
    config:
      default:
        connectTimeout: 5000 #连接超时时间
        readTimeout: 5000   #读超时时间
        loggerLevel: full #日志级别
        errorDecoder: StashErrorDecoder #Feign的错误解码器,这里我们自定义一个
        retryer: CustomRetryer #自定义一个配置重试的方式
        requestInterceptors: FeignRequestInterceptor #自定义请求拦截器
        decode404: false #配置熔断不处理404
logging:
  level:
    com.example.nacosCofigClient.service.BuyerService: debug

feign的错误解码器

/**
 * 自定义一个Feign的错误解码器
 */
@Configuration
public class StashErrorDecoder implements ErrorDecoder {

    @Override
    public Exception decode(String methodKey, Response response) {
        if (response.status() >= 400 && response.status() <= 499) {
            //这里是给出的自定义异常(先用null啦)
            return null;
        }
        if (response.status() >= 500 && response.status() <= 599) {
            //这里是给出的自定义异常(先用null啦)
            return null;
        }
        //这里是其他状态码处理方法(先用null啦)
        return null;
    }
}

feign的请求拦截器

/**
 * 自定义Feign拦截器
 */
public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String values = request.getHeader(name);
                requestTemplate.header(name, values);
            }
        }
    }
}

请求拦截器要注册成bean

@Configuration
public class FeignInterceptorConfig {

    /**
     * feign请求拦截器
     */
    @Bean
    public RequestInterceptor requestInterceptor(){
        return new FeignRequestInterceptor();
    }
}

feign的重试器

@Component
public class CustomRetryer implements Retryer {

    //最大重试次数
    private int retryMaxAttempt;

    //每次重试的间隔时间
    private long retryInterval;

    private int attempt = 1;

    public CustomRetryer(){

    }

    public CustomRetryer(int retryMaxAttempt, Long retryInterval) {
        this.retryMaxAttempt = retryMaxAttempt;
        this.retryInterval = retryInterval;
    }

    /**
     * 在continueOrPropagate方法中,你可以定制你的重试机制。
     * 记住,为了停止重试并且传播错误信息,你必须抛出这个方法收到的retryable异常。
     * 否则,它会继续重试。在这个例子中,我们在尝试我们设定的最大重试次数之后,抛出这个异常,
     * 否则它会在继续下一次重试之前,等待间隔时间(参数)
     * @param e
     */
    @Override
    public void continueOrPropagate(RetryableException e) {
        System.out.println("Feign retry attempt {} due to {} " + attempt + e.getMessage());

        if (attempt++ == retryMaxAttempt) {
            throw e;
        }
        try {
            Thread.sleep(retryInterval);
        } catch (InterruptedException ignored) {
            Thread.currentThread().interrupt();
        }

    }

    /**
     * 返回构造器 6是最大重试次数,2000L时每次重试的间隔时间
     * @return
     */
    @Override
    public Retryer clone() {
        return new CustomRetryer(6, 2000L);
    }
}

3.3feign的日志

在开发或者运行阶段往往希望看到Feign请求过程的日志记录,默认情况下Feign的日志是没有开启的。要想用属性配置方式来达到日志效果,只需配置一下即可
第一种

/**
 * java bean的方式指定日志级别
 * 配置Feign的日志Feign有四种日志级别:
 * 1)NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
 * 2)BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间
 * 3)HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
 * 4)FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据
 */
@Configuration
public class DefaultFeignConfiguration {

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

第二种
在这里插入图片描述
logging.level.xx : debug : Feign日志只会对日志级别为debug的做出响应

logging:
  level:
    com.example.nacosCofigClient.service.BuyerService: debug

3.4Feign使用OKhttp发送request

Feign底层默认是使用jdk中的HttpURLConnection发送HTTP请求,feign也提供了OKhttp来发送请求,具体配置如下:

feign:
  okhttp:
    enabled: true
  hystrix:
    enabled: true

4.Feign原理简述

  • 启动时,程序会进行包扫描,扫描所有包下所有@FeignClient注解的类,并将这些类注入到spring的IOC容器中。当定义的Feign中的接口被调用时,通过JDK的动态代理来生成RequestTemplate。
  • RequestTemplate中包含请求的所有信息,如请求参数,请求URL等。
  • RequestTemplate声场Request,然后将Request交给client处理,这个client默认是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
  • 最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用。

5.feign源码分析

通过上面的使用过程,@EnableFeignClients和@FeignClient两个注解就实现了Feign的功能,那我们从@EnableFeignClients注解开始分析Feign的源码

5.1EnableFeignClients

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
    String[] value() default {};

    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] defaultConfiguration() default {};

    Class<?>[] clients() default {};
}

剩下的看不懂啦
https://baijiahao.baidu.com/s?id=1698639270980356594&wfr=spider&for=pc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值