Feign 入门

本文介绍了Feign的基础概念,包括它的特点和与Retrofit、JAX-RS的关系。详细阐述了Feign在Spring Cloud中的整合,包括步骤和可能出现的问题,如超时设置、日志级别调整、注解替换和配置拦截器的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、简介

1.1 什么是Feign

Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。Feign可帮助我们更加便捷、优雅地调用HTTP API。 Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。Spring Cloud对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便。

Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。 它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

1.2 Feign单独使用

引入依赖

		<dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign‐core</artifactId>
            <version>8.18.0</version>
        </dependency>
        
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-jackson</artifactId>
            <version>8.18.0</version>
        </dependency>

封装

public interface RemoteService {

    @Headers({"Content-Type: application/json","Accept: application/json"})
    @RequestLine("GET /order/findOrderByUserId/{id}")
    public List<Order> findOrderByUserId(@Param("id") Integer id);

    @RequestLine("GET /order/queryInstanceId/")
    public String queryInstanceId();
}

调用

    public static void main(String[] args) {
        RemoteService service = Feign.builder()
                .options(new Request.Options(1000, 3500))
                .retryer(new Retryer.Default(5000, 5000, 3))
                .target(RemoteService.class, "http://localhost:8011/");

        System.out.println(service.queryInstanceId());

        //基于json
        // encoder指定对象编码方式,decoder指定对象解码方式
        service = Feign.builder()
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .requestInterceptor(new MyInterceptor())
                .options(new Request.Options(1000, 3500))
                .retryer(new Retryer.Default(5000, 5000, 3))
                .target(RemoteService.class, "http://localhost:8011/");

        System.out.println(service.findOrderByUserId(1));
    }

2、 Spring Cloud 整合Feign

2.1 整合

第一步:搭建工程service-feign-api ,引入feign依赖

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

第二步:封装接口,添加 @FeignClient 注解

@FeignClient(name = "service-order",path = "/order")
public interface OrderApi {

    @RequestMapping("/findOrderByUserId/{userId}")
    public List<Order> findOrderByUserId(@PathVariable("userId") Integer userId);
}

第三步:将工程 service-feign-api 打成jar包给consumer端使用

第四步:consumer端引入 service-feign-api 依赖

		<dependency>
            <groupId>test.spring.cloud.com</groupId>
            <artifactId>service-feign-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

第五步:在启动类上添加注解@EnableFeignClients

@SpringBootApplication
@EnableFeignClients(basePackages = "test.spring.cloud.com")
public class FeignconsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(FeignconsumerApplication.class, args);
    }
}

第六步:直接使用OrderApi调用接口方法

	 @Autowired
	 private OrderApi orderApi;

    @RequestMapping("/getById/{id}")
    public UserInfoVo getUserById(@PathVariable("id") Integer id) {
 
        List<Order> orderList = orderApi.findOrderByUserId(id);
        UserInfoVo userInfoVo = new UserInfoVo();
    
        return userInfoVo;
    }

注意:接口调用时可能会出现超时异常,SocketTimeoutException: Read timed out
进行超时时间设置:

# ribbon全局超时时间设置
ribbon.ReadTimeout=5000
ribbon.ConnectTimeout=3000

2.2 设置feign的日志级别

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

方式一:设置配置文件

必须配置logging.level ,同时和Ribbon一样,配置类不能被主启动类 @ComponetScan扫描到

#设置Fegin接口的日志级别(接口类)
logging.level.test.spring.cloud.com.feignapi.api.OrderApi = debug
#设置Fegin接口的日志级别(包)
#logging.level.test.spring.cloud.com.feignapi.api = debug
#设置要调用微服务的日志级别 : NONE,BASIC, HEADERS,FULL
#feign.client.config.service-order.loggerLevel=full

方式二:自定义bean

在Feign接口注解上面配置configuration

@FeignClient(name = "service-order",path = "/order",configuration = FooConfiguration.class)
public interface OrderApi {

    @RequestMapping("/findOrderByUserId/{userId}")
    public List<Order> findOrderByUserId(@PathVariable("userId") Integer userId);
}

注册bean设置日志级别

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        //设置日志级别: NONE,BASIC, HEADERS,FULL
        return Logger.Level.FULL;
    }
}

2.3 Feign注解替换

Feign 默认使用的是Spring Mvc 注解,可以通过配置feign.Contract.Default替换 SpringMvcContract 。

注意:如果使用@RequestLine 不配置 Contract.Default契约启动会抛异常。

在Feign接口注解上面配置configuration

@FeignClient(name="service-feign-provider",
        configuration = ProviderConfig.class,path="/order")
public interface MyOrderFeignApi {

    @RequestLine("GET /findOrderByUserId/{userId}")
    public List<Order> findOrderByUserId(@Param("userId") Integer userId);
}

注册bean

@Configuration
public class ProviderConfig {

    @Bean
    public Contract feignContract() {
        //使用feign自带契约
        return new Contract.Default();
    }

    @Bean
    public Logger.Level feignLoggerLevel() {
        //设置日志级别: NONE,BASIC, HEADERS,FULL
        return Logger.Level.FULL;
    }

2.4 配置拦截器

编写拦截器,实现RequestInterceptor接口

public class MyInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        System.out.println("========执行拦截器apply=========");
        requestTemplate.header("token","123456");
    }
}

方式一:注册bean

   @Bean
    public RequestInterceptor myInterceptor() {
        return new MyInterceptor();
    }

方式二:consumer端设置配置文件

#配置拦截器
feign.client.config.service-feign-provider.requestInterceptors[0]=\
  test.spring.cloud.com.feignapi.interceptor.MyInterceptor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值