Feign:熔断,@FeignClient注解参数简介,优化

 相对于RestTemplate来说更加易懂 ,操作方面更加动态化。代码如下:

@GetMapping("/buy/{id}")
public Product order() {
      Product product = restTemplate.getForObject("http://shop-serviceproduct/product/1",Product.class);
      return product;
}

由代码可知,我们是使用拼接字符串的方式构造URL的,该URL只有一个参数。但是,在现实中,URL 中往往含有多个参数。

Feign简介

相关依赖:

<!--springcloud整合的openFeign-->        
        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-openfeign</artifactId>

        </dependency>

Feign是Netflflix开发的声明式,模板化的HTTP客户端。
SpringCloud中,使用Feign非常简单——创建一个接口,并在接口上添加@FeignClient注解。
在消费者的微服务启动类上加上
@EnableFeignClients注解开启Spring Cloud Feign的支持功能。

package com.zb;

import com.zb.service.impl.TestServiceImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ConfigurableApplicationContext;

/**
* 启动类
*/
@EnableFeignClients
@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, 
    }
}

Feign本身不直接支持负载均衡策略,而是通过集成Ribbon来实现负载均衡。因此,Feign可以使用Ribbon支持的各种负载均衡策略,包括轮询、随机、权重、最佳可用等。

服务熔断


SpringCloud Fegin默认已为Feign整合了hystrix,所以添加Feign依赖后就不用在添加hystrix。
yml配置开启熔断

feign:
  hystrix:
    enabled: true
package com.zb.client;

import com.zb.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**   
* feign接口
*/
@FeignClient(value = "user-server",fallback = UserFeignClientImpl .class)
public interface UserFeignClient {

    @GetMapping("/user/all")
    String all(@RequestParam("name")User user);

}
package com.zb.client.impl;

import com.zb.client.UserFeignClient;
import com.zb.entity.User;
import org.springframework.stereotype.Component;

/**
* 熔断方法
*/
@Component
public class UserFeignClientImpl implements UserFeignClient {

    @Override
    public String all(User user) {
        return "异常!";
    }
}

@FeignClient 注解

  注解中参数

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.openfeign;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
    @AliasFor("name")
    String value() default "";

    /** @deprecated */
    @Deprecated
    String serviceId() default "";

    String contextId() default "";

    @AliasFor("value")
    String name() default "";

    String qualifier() default "";

    String url() default "";

    boolean decode404() default false;

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

    Class<?> fallback() default void.class;

    Class<?> fallbackFactory() default void.class;

    String path() default "";

    boolean primary() default true;
}

参数介绍

  1. value 与 name 两者都可指定提供者服务名称。@FeignClient("user-server")默认指定服务名称。
    @FeignClient(value = "user")
    
    @FeignClient(name = "user")
    
    @FeignClient("user")
  2. fallback 与  fallbackFactory
    fallback 定义容错的处理类,当调用远程接口失败或超时时,会调用对应容错方法
    fallbackFactory是可以捕获到Feign接口所有发生的异常,并且同样可以实现fallback相关接口来进行自定义回滚代码或者日志记录等等。还可以减少重复的代码
    @FeignClient(value = 'user', fallback = UserFeignClientImpl.class)
    
    @FeignClient(value = 'user', fallbackFactory = UserFallbackFactory.class)
  3. path这个参数完全不影响Feign接口的使用。

    @FeignClient(value = 'user',path = '/user')
    

    定义当前FeignClient的统一前缀

  4. primary 默认值为true。可以将本类转化成Bean的

  5. url: 用于调试,可以手动指定@FeignClient调用的地址
    @FeignClient(value = 'user',url = "http://localhost:9090/pay/create")
    
  6. decode404 : 默认false,当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException。
    @FeignClient(value = "user-server",decode404 = true)
  7. configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、ContractcontextId:可以位服务名相同的feign接口设定别名来解决同名问题 
    // 第一个feign接口
    @FeignClient(value = "user",contextId = "aa")
    // 第二个feign接口
    @FeignClient(value = "user",contextId = "bb")

Feign性能优化

 主要包括:

  1. 使用带连接池的http请求替代默认的URLConnection
  2. 日志级别,用打印最少的(basic或者none)

1.使用日志 与 超时问题

Feign中本身已经集成了Ribbon依赖和自动配置,因此我们不需要额外引入依赖,也不需要再注册 RestTemplate 对象。负载均衡底层用的就是Ribbon,所以这里的请求超时配置其实就是配置Ribbon,当出现请求超时会出现以下报错。

feign:
  client:
    config:
      default:  #指定feignclients对应的名称 如果指定的是default 表示全局所有的client 的超时时间设置
        connectTimeout: 10000 #连接超时时间
        readTimeout: 10000  #读取超时时间
        loggerLevel: basic #设置日志记录级别

spring:
  main:
    #声明spring框架是否允许定义重名的bean对象覆盖原有的bean(默认是false)
    allow-bean-definition-overriding: true
  1. FULL:记录基本信息以及请求和响应头信息、请求和响应体信息
  2. NONE:没有日志记录
  3. BASIC:记录请求方法、URL以及响应状态代码和执行时间
  4. HEADERS:记录基本信息以及请求和响应头信息

注意 :当开启日志配置之后,feign超时问题不会出现报错情况。

2.使用连接池

HTTP连接需要经过三次握手,四次挥手的过程,这是很耗费性能的;所以HTTP连接池帮助我们节省了这一步。
        同时Feign的HTTP客户端支持三种框架:
        HttpURLConnection、HttpClient、OkHttp;默认是HttpURLConnection

  1. pom.xml中引入Apache的HttpClient依赖
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-httpclient</artifactId>
    </dependency>
    
  2. 配置连接池
    在yml文件中添加如下配置:(连接池引入之后默认是开启的,配合可以不写)
    feign:
      client:
        config:
          default:
            loggerLevel: BASIC
      httpclient:
        enabled: true #开启feign对httpClient的支持
        max-connections: 200 #最大的连接数
        max-connections-per-route: 50 #每个路径的最大连接数
    

3.gzip压缩

Gzip 是GNUzip的缩写,最早用于UNIX系统的文件压缩。gzip压缩比率在3到10倍左右,可以大大节省服务器的网络带宽。而在实际应用中,并不是对所有文件进行压缩,通常只是压缩静态文件。


server:
  compression:
    enabled: true #开启压缩

Gzip解压缩代码实现

        1.运行虚拟机
        2.在Idea的Maven中打包代码
        3.将打包文件拖入虚拟机中
        4.执行jar包

客户端和服务器之间通信支持gzip图

常见问题

Feign 的 maven 依赖报红,或者主启动类上@EnableFeignClients不识别,一直报红,或者 feign 接口注入到控制器报红。
可能的原因及处理方案:
        1.maven 包没有成功导入,或者 maven 包下载不完整,可以先clean在compile一下删掉依赖包后重新下载导入。
        2.版本冲突,可以在 maven 包导入时指定版本号,尝试其他可用的版本。

面试题

1.Feign与RestTemplate之间有什么区别?
Feign和RestTemplate都用于进行HTTP请求,但它们有一些区别:
    Feign:
        Feign是声明性的HTTP客户端,通过接口和注解来定义服务调用。
        Feign自动生成HTTP请求代码,开发者只需定义接口和方法。
        集成了Ribbon和Hystrix,支持负载均衡和服务降级。
        更具有声明性和简洁性,适用于微服务架构中的服务调用。
    RestTemplate:
        RestTemplate是经典的HTTP客户端,需要手动编写HTTP请求代码。
        开发者需要构建HTTP请求、处理请求和响应、处理异常等。
        可以用于调用任何HTTP服务,不仅限于微服务架构。
        更灵活,适用于需要更多控制的场景。
    选择使用Feign还是RestTemplate取决于项目的需求和开发团队的偏好。在微服务架构中,Feign通常更受欢迎,因为它提供了更高级别的抽象和更简洁的代码。

2.使用Feign时怎样传递Header的参数?

// 1.通过 @RequestHeader(name = "name") 来传递
@FeignClient(name = "xxx-service-name")
public interface XxxFeignClient {
 
    @RequestMapping(value = "/user/info")
    String userTicket(@RequestHeader(name = "token") String token);
}

这种方式的缺点和明显,就是如果传递多个Header参数,则需要在接口方法定义的时候都添加进去,显得比较繁琐。
第二种方式,就是通过定义一个配置类实现RequestInterceptor接口,然后将这个配置类添加进@FeignClient注解中即可,代码示例如下:

@Configuration
public class HeaderConfiguration implements RequestInterceptor {
    
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
 
        Enumeration headerNames = request.getHeaderNames();
 
        if (headerNames != null) {
            // 循环取所有header,将header的内容都放入requestTemplate
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String values = request.getHeader(name);
                requestTemplate.header(name, values);
            }
        }
    }
}
// 然后将自定义的配置类配置到Feign中,实现该Feign中接口Header参数的传递
@FeignClient(value = "user-server", configuration = HeaderConfiguration.class)
public interface UserFeignClient {
 
    @RequestMapping(value = "/user/info")
    String userInfo();
}


        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值