SpringCloud-服务之间的调用OpenFeign

OpenFeign

1.什么是OpenFeign

  Feign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样简单, 只需要创建一个接口并添加一个注解即可。

2. openfeign的使用

  2.1 Nacos整合Open-Feign负载均衡

  2.2 Nacos注册中心、Ribbon负载均衡、OpenFeign服务调用

    Nacos很好的兼容了Feign, Feign负载均衡默认集成了 Ribbon, 所以在Nacos下使用Fegin默认就实现了负载均衡的效果。

   2.3  OpenFeign实现负载均衡代码演示、

    - SpringCloudAlibaba中使用OpenFeign时,默认的负载均衡策略是轮询调用

    项目启动的时候,会用LoadBalancerFeignClient注册一个feign.Client到ioc容器中,

    FeignClientFactoryBean会生成一个@FeignClient注解的对应的service实例。

    - openfeign底层用的也是ribbon负载均衡组件
  -- 如何使用? 
    pom中引入依赖;主程序类上添加注解 @EnableFeignClients;定义用于调用服务提供者的 Feign 接口
  -- opfenFeign 常用配置?
    1.feign的超时配置
    2.负载均衡策略配置 默认是轮询
  -- 自定义拦截器
    处理服务间调用cookie传值! 
  
  
     

3. 负载均衡

  通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。

  根据负载均衡发生位置的不同,一般分为服务端负载均衡客户端负载均衡

  服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡

  而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求

  我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行.

 4. 对比 Netflix Feign 和 OpenFeign

  4.1 后来Netflix内部不在使用Feign并停止更新,为此Netflix把Feign提交给开源社区,命名为OpenFeign

5.openfeign设置超时 我有个问题 设置1秒,正常调用服务方,这个超时是因为服务方处理业务逻辑复杂或者调用第三方产生的时间大于1秒,这个时候 如何处理; 

   超时时间长一些 或者 查证交易 

  5.1 OpenFeign 实践之 FeignClient 超时设置

6. openfeign超时配置

  6.1 openfeign设置超时时间与日志增强  ribben控制无效

  

     OpenFeign 客户端默认等待1秒钟,但是如果服务端业务超过1秒,则会报错。为了避免这样的情况,我们需要设置feign客户端的超时控制。

      办法:由于OpenFeign 底层是ribbon 。所以超时控制由ribbon来控制。在yml文件中配置

复制代码
feign:
  client:
    config:
      default:
        #建立连接所用的时间,适用于网络状况正常的情况下,两端连接所需要的时间, 连接超时
        ConnectTimeOut: 5000
        #指建立连接后从服务端读取到可用资源所用的时间,默认为1s,请求处理处理的超时时间
        ReadTimeOut: 5000
----

  #设置Feign客户端超时时间(openfeign默认支持ribbon

   ribbon:

       ConnectTimeout: 5000

 

    ReadTimeout:  5000

 

复制代码

   6.2 如果我们没有配置feign超时时间,上面的时间也会被ribbon覆盖?请求连接时间和超时时间,默认为1秒

 

 7.OpenFeign的使用步骤
  7.1 子模块pom中 引入依赖 去掉ribbon中的archaius依赖,防止警告 openFeign/nacos 都内置了Ribbon,如果没有强迫症 也可以带着 警告无所谓
复制代码
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-cloud-netflix-archaius</artifactId>
                    <groupId>org.springframework.cloud</groupId>
                </exclusion>
            </exclusions>
        </dependency>
复制代码

  7.2 主启动类 引入 @EnableFeignClients 开启Feign客户端

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

  7.3 新建PaymentFeignService接口并新增注解@FeignClient(value="调用注册中心微服务名")

复制代码
@Component
@FeignClient(value = "cloud-payment-service") //请求地址
public interface PaymentFeignService {
    
  // 直接复制的 服务提供方的方法 @GetMapping(value
= "/payment/nacos/{id}") //请求路径 public String getPayment(@PathVariable("id") Long id) ; @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(); }
复制代码

  7.4 注入接口PaymentFeignService 使用

复制代码
/**
 * nacos 的消费方的 服务
 */
@RestController
@Slf4j
public class NacosController {

    @Autowired
    //调用远程的微服接口
    private PaymentFeignService paymentFeignService;

    @GetMapping(value = "/consumer/payment/nacos/{id}")
    public String paymentInfo(@PathVariable("id") Long id) {
        return paymentFeignService.getPayment(id);
    }
}
复制代码

 

8.OpenFeign开启日志打印

  8.1 配置日志bean

复制代码
package com.tsbx.common.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}
复制代码

  8.2  YML文件里需要开启日志的Feign客户端

logging:
  level:
    com.tsbx.business.nacos.controller.service.PaymentFeignService: debug

 

 

9.超时控制 openFeign 默认请求处理的时间为1秒

  9.1 超时分两种 一种是连接超时,

  一种是连接通了,读取超时

 #设置Feign客户端超时时间(openfeign默认支持ribbon)
   ribbon:
     ConnectTimeout: 5000
     ReadTimeout:  5000

   9.2 openFeign常用注解及超时时间规则详解 

    由于openFeign内部集成了ribben和Feign 所以可以通过两方面配置

    1.配置ribben  默认连接和读取是1秒 默认

    2.配置Feign 默认连接10s 读取60s 如果不配置会被ribbon覆盖

 

10.openfeign ribbon过期时间无效 

  openfeign超时配置的坑,超时配置不生效 debug 源码调试

feign:
  client:
    config:
      default:
        #建立连接所用的时间,适用于网络状况正常的情况下,两端连接所需要的时间
        ConnectTimeOut: 5000
        #指建立连接后从服务端读取到可用资源所用的时间
        ReadTimeOut: 5000

 

11.OpenFegin整合Ribbon和Hystrix,为微服务中远程调用提供了一种更优雅的调用方式,它支持负载均衡和容错熔断机制。通过上面的例子,在SpringCloud中接入Nacos做注册中心后,并不会影响我们继续使用其他SpringCloud组件。 

 @FeginClient注解指定被调用方的服务名,通过fallback属性指定RemoteHystrix类,来进行远程调用的熔断和降级处理。

   降级的例子上边连接

 

12. OpenFeign的降级配置 需要用的Hystrix fallback

  12.1 子系统中pom中引入依赖

       <!--熔断降级使用-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

  12.2 yml 开启

feign:
  hystrix:
    enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。

  12.3 主启动  @EnableHystrix

  12.4 业务

 

复制代码
@FeignClient(name = "nacos-provide",fallback = RemoteHystrix.class)
public interface RemoteClient {

    @GetMapping("/helloNacos")
    String helloNacos();
}


@Component
public class RemoteHystrix implements RemoteClient {
    @Override
    public String helloNacos() {
        return "请求超时了";
    }
}
复制代码

 

  12.5   服务降级Fallback

    服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示

    场景: 超时、程序异常

 

13. 服务熔断Breaker

  13.1 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

    服务的降级->进而熔断->恢复调用链路

   13.2  Hystrix会监控微服务间调用的状态,当失败的调用到一定阈值,缺省是5秒内20调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand

 

14. 服务限流Flowlimit

  14.1 秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

 

 

 

15.为什么要替换 OpenFeign 默认 httpUrlConect 的使用 HttpClient 

  15.1 SpringCloud OpenFeign使用OkHttp,添加响应拦截器 同样 httpClient 也可以使用拦截器,好处是可以使用默认连接池

    SpringCloud微服务之间的请求一般使用OpenFeign,有时候我们需要在请求或者响应的时候做一些额外的操作。比如请求的时候添加请求头,响应的时候判断token是否过期等等。这时候拦截器就派上用场了

   15.2 区别   

      --HTTP 连接池
    在HTTP 通信的过程中,建立连接是一个很复杂的过程,涉及到多个数据包的交换,很耗时间,而且HTTP连接需要3次握手和4次挥手开销都很大。

    这时可以采用HTTP连接池,节约大量的3次握手4次挥手时间,提升吞吐量。

    Feign、Ribbon 默认的HttpURLConnection是JDK自带的,并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。

    HttpClient 相比传统JDK自带的HttpURLConnection,它封装了访问HTTP的请求头,参数,内容体,响应等等。它不仅使客户端发送HTTP请求变得容易,而且也方便了开发人员测试接口(基于HTTP协议的),既提高了开发的效率,又提高了代码的健壮性。另外高并发大量的请求网络的时候,也是用"连接池"提升吞吐量。涉及Session、Cookie的处理

    OkHttp作为后期之秀,功能和性能上,可能稍优于HttpClient ,但是几乎没多大区别,实际使用时,都是可以的,不过HttpClient集成起来更方便。

      --Httpclient 连接池 提供了默认的配置项

    

  15.3 如果不做特殊配置,OpenFeign默认使用jdk自带的HttpURLConnection,我们知道HttpURLConnection没有连接池、性能和效率比较低,如果采用默认,很可能会遇到性能问题导致系统故障。

  15.4 步骤 引入依赖

    

 

  yml 开启httpClient

    

 

 

 

16. openfeign调用 HttpServletRequest作为参数 报错..  可以传递cookie 进行jwt验证  ,微服务之间调用 传递 httpServletRequest 对象

  16.1 问题分析 

  1. feign接口是不支持HttpServletRequest作为参数的
  2. feign和hystrix整合开启了feign对hystrix的熔断,导致feign的拦截器获取不到请

  16.2 解决

    问题1解决, 使用feign的拦截器,将请求拦截下

复制代码
package top.bitqian.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author echo lovely
 * @date 2021/2/1 20:45
 */
@Configuration
public class FeignInterceptor implements RequestInterceptor {
        /**
         * 复写feign请求对象
         * @param requestTemplate hhh
         */
        @Override
        public void apply(RequestTemplate requestTemplate) {
            //获取请求头
            Map<String,String> headers = getHeaders(Objects.requireNonNull(getHttpServletRequest()));
            for(String headerName : headers.keySet()){
                requestTemplate.header(headerName, getHeaders(getHttpServletRequest()).get(headerName));
            }
        }
        //获取请求对象
        private HttpServletRequest getHttpServletRequest() {
            try {
                return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        //拿到请求头信息
        private Map<String, String> getHeaders(HttpServletRequest request) {
            Map<String, String> map = new LinkedHashMap<>();
            Enumeration<String> enumeration = request.getHeaderNames();
            while (enumeration.hasMoreElements()) {
                String key = enumeration.nextElement();
                String value = request.getHeader(key);
                map.put(key, value);
            }
            return map;
        }

}
复制代码

    这样feign接口中,就不用写HttpServletRequest 请求了,请求会通过feign发送到提供者。

 

    问题二解决:造成原因,feing.hystrix.enabled=true, 开启了熔断

      解决,将上面配置更换为:

hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE

 

17.关于openfeign的参数传递  接口传参



18.openfeign 使用 httpclient的时候 pom文件 不要引入版本号 否则报错

  java.lang.IllegalStateException: original request is required

 

19. 关于openfeign ;使用集成httpclient 使用其默认的连接池

    由于 openfeign 使用Ribbon 进行负载均衡 默认轮询;

    Ribbon默认也是用jdk自带的HttpURLConnection,需要给Ribbon也设置一个Http client 

# ribbon 使用httpclient  替换默认 httpUrlConnection
ribbon:
http:
client:
enabled: true

 

 20.开启hystrix 并且想要实现openFeign httpserveletRequest 传递怎么处理,首先使用feign的拦截器,将请求拦截下; 即开了hystrix 的熔断降级 也要实现httpServletRequest传递

  hystrix:
    enabled: true
    command:
      default:
        execution:
          isolation:
            strategy: SEMAPHORE

由于 开启hystrix后,feign请求,会运行在hystrix管理的另一线程下。也就是说从请求方模块发送到服务方的请求参数可以正常传递,但是HttpServletRequest request对象并没有正常传递,从一个线程到另一个线程中时,request并没有跟随一起。需要手工组装request请求中的值。

  20.1  创建一个自定义的hystrix 线程策略, 将servletRequestAttributes传入新线程中,并赋给RequestContextHolder:

复制代码
public class MyHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable){
        ServletRequestAttributes servletRequestAttributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return new Callable<T>() {
            @Override
            public T call() throws Exception {
                try {
                    if (null != servletRequestAttributes) {
                        RequestContextHolder.setRequestAttributes(servletRequestAttributes);
                    }
                    return callable.call();
                }finally {
                    RequestContextHolder.resetRequestAttributes();
                }
            }
        };
    }
}
@Configuration
public class HystrixConfig {
    @PostConstruct
    public void init(){
        HystrixPlugins.getInstance().registerConcurrencyStrategy(
                new MyHystrixConcurrencyStrategy()
        );
    }
}
复制代码

 

 21.curl 携带cookie 数据

 

 22. Ribbon和OpenFeign

  1.Ribbon侧重于做服务调用时的负载均衡,而OpenFeign侧重于面向接口进行服务调用。

  2.OpenFeign自身集成Ribbon,所以默认开启轮询的负载均衡

  3.我们不用过多去研究ribbon,它只是一个提供负载均衡的,大多时候只是更改负载均衡的算法。我们只需要编写好feign的接口以及其降级实现类, 所以引入依赖时,只用引入OpenFeign即可。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
 
 
posted @   BBS_自律  阅读(570)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
点击右上角即可分享
微信分享提示