SpringBoot整合Feign

推荐参考:Spring Cloud Ribbon 介绍

1、Feign-简介

Feign是Neflix开发的声明式、模块化的HTTP客户端,集成了RibbonRestTemplate实现了负载均衡的执行Http调用,Feign可以帮助我们更加便捷、优雅的调用HTTP API。

Spring Cloud OpenFeign是对Feign的增强,使其支持Spring MVC 注解,另外还整合了Ribbon和Nacos,从而是的Feign使用更加方便,有了feign我们就不用使用resttemplate远程调用了(调用Controller层)。

Feign 和 OpenFeign区别

1. 维护者和状态:

  • Netflix Feign:Netflix公司最初开发了Feign,但后来决定停止其维护。
  • OpenFeign:由于Netflix不再维护Feign,Feign由Spring Cloud社区接管并更名为OpenFeign。OpenFeign是Feign的后续版本,由社区维护,并且项目已经迁移到新的仓库。

2. 依赖和集成:

  • Netflix Feign:在Netflix维护期间,Feign是一个独立的组件,主要用于Spring Cloud中的服务调用。
  • OpenFeign:OpenFeign是基于Netflix Feign的改进版本,并集成了Spring MVC的注解等,使其更方便地与Spring Boot项目集成。Spring Cloud官方推荐使用OpenFeign,并通过spring-cloud-starter-openfeign依赖来提供支持。

2、spring-cloud快速整合OpenFeign

1)在调用服务中添加依赖

<!--添加openfeign依赖,依赖于sprin-cloud-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2)配置需要调用的接口

/*
 * name 指定调用rest接口对应服务名
 * path 指定调用接口所在Controller的@RequestMapping对应路径,没有则不填
 */
@FeignClient(name = "stock-service", path = "/stock")
public interface StockFeignService {
    // 声明需要调用的接口方法名
    @PostMapping("/reduct")
    String add(@RequestParam("name") String name);
}

3)启动类加上注解

@EnableFeignClients

4)直接调用

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private StockFeignService stockFeignService;

    @GetMapping("/getOrder")
    public String getOrder(){
        stockFeignService.add("10");
        return "Hello world";
    }
}

注:使用feign需要在参数前面加上@RequestParam和@PathVariable注解并指定参数,不然获取不到参数。

3、Feign日志

1)feign日志级别:

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

2):配置feign日志:

package com.swp.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// 全局配置: 使用@Configuration会全局配置到所有服务提供方(被调用方)
// 局部配置: 如果只针对某个服务,就不要使用@Configuration,在@FeignClient(name = "stock-service", path = "/stock", configuration = FeignClient.class)中加入configuration = FeignClient.class

@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLogerLevel(){
        return Logger.Level.FULL;
    }
}

yaml配置日志级别

#spring 默认日志级别是info,feign的debug日志不会输出,所以需要配置输出日志级别
logging:
  level:
    com.swp.feign: debug #只输出feign目录下的日志

日志输出:
在这里插入图片描述

4、Feign契约配置

若以前使用的feign原生注解,在不想改变原生注解的情况下,可以使用Feign契约配置

feign:
	client:
		config:
			contract: feign.Contract.Default
	

5、Feign配置超时时间

全局配置:

@Configuration
public class FeignConfig(){
	@Bean
	public Request.Options options(){
		return new Request.Options(5000,10000);
	}
}

yaml配置

feign:
	client:
		config:
			mall-order: #对应微服务
			# 连接超时时间。默认2s
			connectTimeout: 5000
			# 请求处理超时时间,默认5s
			readTimeout: 10000

6、Feign拦截器

在服务消费者调用服务提供者时触发。
Feign拦截器配置类

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CustomFeignInterceptor implements RequestInterceptor {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("token", "123");
        requestTemplate.query("name", "999");
        // requestTemplate.uri("/111"); 拦截所有路径,并修改为/{xx}
        logger.info("feign拦截器");
    }
}

注入配置类

 // 注入自定义feign拦截器
    @Bean
    public CustomFeignInterceptor customFeignInterceptor(){
        return new CustomFeignInterceptor();
    }
}

7、Feign断路器

#开启hysrris
feign:
  hystrix:
    enabled: true

定义SysMgrHystrix ,实现FallbackFactory的create方法来提供服务降级实现类对象的创建,
ServiceSysMgrClient是自己的feign接口

@Component
public class SysMgrHystrix implements FallbackFactory<ServiceSysMgrClient> { 

    @Override
    public ServiceSysMgrClient create(Throwable throwable) {
        return new ServiceSysMgrClient() {
           // 下面是feign接口
            @Override
            public Result<List<OrgNode>> getOrgChildren(Integer parentOrgId) {
                return "被回滚了";
            }
        };
    }
}

然后在Feign接口上面加上 fallbackFactory = SysMgrHystrix.class
在这里插入图片描述

8、Feign 相关问题

推荐参考:Spring Cloud Ribbon 介绍

8.1 Feign 如何实现负载均衡

Feign内部集成了Ribbon,用于处理服务之间的负载均衡。Ribbon是一个可插拔的客户端负载均衡器,它可以在运行时动态地从“服务中心”(如Eureka、Consul等)获取服务实例列表,并根据配置的负载均衡策略选择一个服务实例进行调用。

8.2 为什么Feign第一次调用耗时较长?

这通常是由于Ribbon的懒加载机制。当第一次通过Feign客户端发起调用时,Ribbon需要执行一系列操作,包括从服务注册中心(如Eureka、Consul等)获取服务实例列表、建立连接池等,这些操作会导致首次调用的延迟。

如何解决这个问题?

1.采用饥饿加载

ribbon:  
  eager-load:  
    enabled: true  
    clients: service-1,service-2 # 列出所有需要预加载的服务

请注意,clients属性应该是一个逗号分隔的服务名列表。但是,不是所有的服务注册中心都支持Ribbon的eager-load功能,因此这可能不适用于所有情况。

2.应用启动时预热Feign客户端

如果eager-load不起作用,或者您想要更细粒度的控制,您可以在应用启动时编写一些代码来预热Feign客户端。这可以通过在Spring Boot的@PostConstruct注解的方法中执行一个无关紧要的Feign调用来实现。

例如:

@Component  
public class FeignClientInitializer {  
  
    private final MyFeignClient myFeignClient;  
  
    @Autowired  
    public FeignClientInitializer(MyFeignClient myFeignClient) {  
        this.myFeignClient = myFeignClient;  
    }  
  
    @PostConstruct  
    public void init() {  
        // 执行一个无关紧要的调用来预热Feign客户端  
        try {  
            myFeignClient.someInnocuousMethod(); // 假设这个方法不会造成实际影响  
        } catch (Exception e) {  
            // 记录或忽略异常,因为这只是预热调用  
        }  
    }  
}

8.3 Feign怎么实现认证传递?

因为请求到服务是通过 HandlerInterceptor 传递认证信息(如OAuth令牌、JWT令牌或其他认证令牌),但是通过openfeign调用时在HandlerInterceptor是没有认证信息的。

在Feign中传递认证信息的常见做法是通过实现RequestInterceptor接口来定义一个拦截器。拦截器允许你在请求发送之前对请求进行修改,比如添加请求头。以下是使用Feign和RequestInterceptor来传递认证信息的步骤:

import feign.RequestInterceptor;  
import feign.RequestTemplate;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
  
@Configuration  
public class FeignClientConfig {  
  
    @Autowired  
    private AuthService authService; // 假设AuthService是一个Spring管理的Bean  
  
    @Bean  
    public RequestInterceptor requestInterceptor() {  
        return new RequestInterceptor() {  
            @Override  
            public void apply(RequestTemplate template) {  
                //AuthService获取JWT令牌并添加到请求头中  
                String authHeader = "Bearer " + authService.getJwtToken();  
                template.header("Authorization", authHeader);  
            }  
        };  
    }  
}  
  
  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值