Featured image of post OpenFeign

OpenFeign

Java微服务学习笔记之OpenFeign远程调用

OpenFeign—远程调用

使用OpenFeign进行远程调用

向第三方微服务API发送请求

小Tips:向自己的业务API发送请求直接复制对方业务Controller层方法即可

前面使用的是restTemplate进行远程调用,但是使用restTemplate进行远程调用比较麻烦,这里我们使用OpenFeign改写代码

导入依赖,创建ProductFeignClient接口

1
2
3
4
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
restTemplate
package com.example.feign;

import com.example.bean.product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "product-service")   //Feign客户端,指定要请求的服务名称
public interface ProductFeignClient {

    //MVC注解两套逻辑
    //标注在controller上,是接收http请求
    //标注在feign上,是用来发送http请求
    @GetMapping("/product/{productId}")   //指定远程服务接口
    product getProductById(@PathVariable("productId") Long productId);
}

将ProductFeignClient进行依赖注入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    @Autowired
    ProductFeignClient productFeignClient;

    @Override
    public order CreateOrder(Long userId, Long productId) {
        order order = new order();
        //调用接口的方法发送请求
        product product = productFeignClient.getProductById(productId);
        //不需要自己在写getProductFromRemote2方法
        //product product = getProductFromRemote2(productId);
        order.setId(1L);
        //计算订单总金额
        order.setTotalAmount(product.getPrice().multiply(new BigDecimal("10")));
        order.setUserId(userId);
        order.setNikeName("zhangsan");
        order.setAddress("beijing");
        //远程查询商品信息,并设置到订单中
        order.setProductList(Arrays.asList(product));
        return order;
    }

第三方API远程调用

比如我不需要像注册中心发请求,我想像第三方API发送请求,如:墨迹天气等等

使用FeignClient绑定第三方API的URL,根据对应请求方法发送对应请求

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.example.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

//https://v.api.aa1.cn/api/api-tianqi-3/index.php?msg=%E5%A4%A9%E6%B4%A5&type=1
@FeignClient(value = "weather",url = "https://v.api.aa1.cn/api/api-tianqi-3/index.php")
public interface WeatherFeignClient {

    @GetMapping("/api/api-tianqi-3/index.php")
    String getWeather(@RequestParam("msg") String msg,
                    @RequestParam("type") String type);

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package com.example;

import com.example.feign.WeatherFeignClient;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class WeatherTest {

    @Autowired
    WeatherFeignClient weatherFeignClient;

    @Test
    void test(){
        String weather = weatherFeignClient.getWeather("北京", "1");
        System.out.println(weather);
    }
}

客户端负载均衡与服务端负载均衡?

OpenFeign进阶配置

开启请求日志功能

在yml配置文件中配置日志的范围

1
2
3
logging:
  level:
    com.example.feign: debug

在config配置类中配置一个Bean

1
2
3
4
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

再次运行测试类,请求的详细信息(请求方法,路径,参数都会展示)

超时控制

超时有两种超时,连接超时(默认10秒)和读取超时(默认60秒)

可以新创建一个配置文件,如果其它配置文件想要使用这个配置文件的话只需要引用即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
spring:
  cloud:
    openfeign:
      client:
        config:
          product-service:                 #            只针对product-service服务的配置
            connect-timeout: 10000        #            连接超时时间
            read-timeout: 10000          #            读取超时时间
            logger-level: full          #            日志级别
          default:                         #            所有其它服务的默认配置
            connect-timeout: 20000        #            连接超时时间
            read-timeout: 30000          #            读取超时时间
            logger-level: full          #            日志级别

重试机制

在config配置类中自定义一个重试器retryer,Spring提供默认的retryer,默认最大重试5次,每次最大间隔1秒

1
2
3
4
5
    @Bean
    Retryer retryer() {
        //最多重试3次,每次最大间隔10秒,最小间隔1秒
        return new Retryer.Default(1000, 10000, 3);  
    }

拦截器

创建好后可以将这个拦截器在配置文件中声明也可以将它设置为Bean,自动调用拦截

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.example.interceptor;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component          
public class TokenRequestInterceptor implements RequestInterceptor {

    /*
    * 请求拦截器需要实现RequestInterceptor接口的apply方法
    * 该方法会在请求发送之前被调用
    * 可以在该方法中添加请求头、请求参数等
    * 这里我们可以通过RequestTemplate对象来添加请求头
    * 例如:requestTemplate.header("Authorization", "Bearer " + token);
    * */
    @Override
    public void apply(RequestTemplate requestTemplate) {
        System.out.println("拦截器执行了");
        requestTemplate.header("Authorization", UUID.randomUUID().toString());
    }
}

Fallback兜底返回

使用Fallback兜底返回机制需要引入sentinel依赖

1
2
3
4
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

在配置文件中将feign.sentinel.enable设置为true

1
2
3
feign:
  sentinel:
    enabled: true                       #            开启feign对sentinel的支持

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.feign.fallback;

import com.example.bean.product;
import com.example.feign.ProductFeignClient;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;

@Component
public class ProductFeignClientFallback implements ProductFeignClient {
    @Override
    public product getProductById(Long productId) {
        System.out.println("兜底回调");
        product product = new product();
        product.setId(productId);
        product.setProductName("兜底回调商品");
        product.setPrice(new BigDecimal("1000.00"));
        product.setNum(10);
        return product;
    }
}

如果正常请求无法完成请求,那么会走兜底回调方法,返回默认数据

By Lsec
最后更新于 Jun 08, 2025 15:21 +0800
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计
¹鵵ҳ