SpringCloud Alibaba微服务 -- OpenFeign的使用(保姆级)

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介: SpringCloud Alibaba微服务 -- OpenFeign的使用(保姆级)

openFeign的使用

1、openFeign是干什么的?

OpenFeign是一个显示声明式的WebService客户端。使用OpenFeign能让编写Web Service客户端更加简单。使用时只需定义服务接口,然后在上面添加注解。OpenFeign也支持可拔插式的编码和解码器。spring cloud对feign进行了封装,使其支持MVC注解和HttpMessageConverts。和eureka(服务注册中心)和ribbon组合可以实现负载均衡。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求,非常的方便

2、建立服务模块

建立order订单模块服务(之前文章已经建立了user服务),这样两个服务就可以测试feign接口了。

user服务的建立请看第一篇文章 https://blog.csdn.net/qq_38374397/article/details/125542389

新建maven子模块

application.yml配置文件

server:
  port: 9091
spring:
  application:
    name: mdx-shop-order
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: mdx
        group: mdx

bootstrap.properties配置文件

spring.application.name=mdx-shop-order
spring.cloud.nacos.config.server-addr=localhost:8848
spring.cloud.nacos.config.extension-configs[0].data-id=mdx-shop-order.yaml
spring.cloud.nacos.config.extension-configs[0].group=shop
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.file-extension=yml
spring.cloud.nacos.config.namespace=mdx
spring.cloud.nacos.config.group=shop

3、引入依赖

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

4、openFeign的使用

我们先创建一个common的公共模块,然后引入一些工具类

在common中添加工具类,一些字符串操作和非空判断

在其他模块中引用common公共模块

在order服务中先创建一个获取订单号的测试接口

建立一个controller层和service层,controller层代码分别如下:

@RestController
@RequestMapping("/order")
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    @GetMapping("getOrderNo")
    public String getOrderNo(String userId){
        return orderService.getOrderNo(userId);
    }
}

service层实现类,目前没有查DB,做了简单的判断

@Service
public class OrderServiceImpl implements OrderService {
    @Override
    public String getOrderNo(String userId) {
        if (StringUtils.isNotEmpty(userId) && userId.equals("mdx123456")){
            return "O111222333444";
        }
        return "订单不存在";
    }
}

在启动类开启支持feign的远程调用的注解 @EnableFeignClients

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

然后在user服务中创建一个OrderFeign接口用来调用order服务

@FeignClient(value = "mdx-shop-order")
@Component
public interface OrderFeign {
    @GetMapping("order/getOrderNo")
    String getOrderNo(String userId);
}

@FeignClient标签的常用属性如下:

  • name/value:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
  • url: url一般用于调试,可以手动指定@FeignClient调用的地址
  • decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
  • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
  • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
  • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
  • path: 定义当前FeignClient的统一前缀,当我们项目中配置了server.context-path,server.servlet-path时使用

value 属性的值是order服务的服务名称,也就是注册到注册中心中的服务名称

我们在user服务中建立一个controller和service调用feign接口来测试一下

controller层

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("getOrderNo")
    public String getOrderNo(String userId){
        return userService.getOrderNo(userId);
    }
}

service层

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private OrderFeign orderFeign;
    @Override
    public String getOrderNo(String userId) {
        return orderFeign.getOrderNo(userId);
    }
}

分别启动user服务和order服务测试

启动user服务的时候发现报错了,是因为SpringCloud Feign在Hoxton.M2 RELEASED版本之后抛弃了Ribbon,使用了spring-cloud-loadbalancer,所以我们这里还需要引入spring-cloud-loadbalancer的依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
            <version>3.1.1</version>
        </dependency>

重新启动项目,并查看nacos,发现服务已经注册成功

接下来访问user服务,看看是否能通过feign接口成功获取到订单号

user服务报错

feign.FeignException$MethodNotAllowed: [405] during [GET] to [http://mdx-shop-order/order/getOrderNo] [OrderFeign#getOrderNo(String)]: [{"timestamp":"2022-07-04T03:13:30.111+00:00","status":405,"error":"Method Not Allowed","path":"/order/getOrderNo"}]

order服务提示信息

2022-07-04 11:13:30.110  WARN 66016 --- [nio-9091-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]

通过意思信息我们可以发现,我们的GET请求被当成了POST请求,如果不加默认的注解,Feign则会对参数默认加上@RequestBody注解,而RequestBody一定是包含在请求体中的,GET方式无法包含

我们改变一下feign接口,添加一个@RequestParam注解

@FeignClient(value = "mdx-shop-order")
@Component
public interface OrderFeign {
    @GetMapping("order/getOrderNo")
    String getOrderNo(@RequestParam String userId);
}

重启user服务,访问接口测试

成功获取到order服务中的订单号

5、openfeign接口添加请求头信息

我们有时候会在接口请求中传递一些头信息,来看一下feign是怎么使用的

其中有5种方式可以实现传递请求头信息:

  • 在@RequestMapping注解里添加headers属性
  • 在方法参数前面添加@RequestHeader注解
  • 在方法或者类上添加@Headers的注解
  • 在方法参数前面添加@HeaderMap注解
  • 实现RequestInterceptor接口

我们只演示一个最简单的,在方法参数前面添加@RequestHeader注解

修改一下OrderFeign接口

单个参数:

@GetMapping("order/getOrderNo")
    String getOrderNo(@RequestParam String userId,@RequestParam String tenantId,@RequestHeader("Authorization") String token);

多个参数使用MultiValueMap

@GetMapping("order/getOrderNo")
    String getOrderNo(@RequestParam String userId, @RequestParam String tenantId, @RequestHeader MultiValueMap<String, String> headers);

我们来测试下传递单个参数的情况

user服务代码修改:

controller(添加HttpServletRequest参数):

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("getOrderNo")
    public String getOrderNo(String userId,String tenantId,HttpServletRequest request){
        return userService.getOrderNo(userId,tenantId,request);
    }
}

service实现类(获取request中的头信息并传递给feign接口)

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private OrderFeign orderFeign;
    @Override
    public String getOrderNo(String userId, String tenantId, HttpServletRequest request) {
        return orderFeign.getOrderNo(userId,tenantId, request.getHeader("token"));
    }
}

order服务:

controller(获取头信息中的参数):

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;
    @GetMapping("getOrderNo")
    public String getOrderNo(String userId, String tenantId, HttpServletRequest request){
        System.out.println("Authorization:" + request.getHeader("Authorization"));
        return orderService.getOrderNo(userId,tenantId);
    }
}

重启服务并调用接口

成功获取到头信息

6、fallback的使用

来看一下fallback属性的作用

fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口

然后我们看下怎么用

先定义一个容错的处理类 OrderFeignHandler:

@Component
public class OrderFeignHandler implements OrderFeign {
    @Override
    public String getOrderNo(String userId, String tenantId, String token) {
        String fallback = "当前人数过多,休息一会再试";
        return fallback;
    }
}

@FeignClient 注解添加fallback属性 fallback = OrderFeignHandler.class

@FeignClient(value = "mdx-shop-order",fallback = OrderFeignHandler.class)
@Component
public interface OrderFeign {
    @GetMapping("order/getOrderNo")
    String getOrderNo(@RequestParam String userId,@RequestParam String tenantId,@RequestHeader("Authorization") String token);
}

重启user服务,先获取一下正常的数据

正常返回订单号

我们在模拟一下异常的情况 修改order服务中的获取单号接口,找不到单号则抛异常

@Service
public class OrderServiceImpl implements OrderService {
    @Override
    public String getOrderNo(String userId,String tenantId) {
        System.out.println(tenantId);
        if (StringUtils.isNotEmpty(userId) && userId.equals("mdx123456")){
            return "O111222333444";
        }else {
            throw new RuntimeException("单号不存在");
        }
    }
}

重启order服务,参数中传递一个不存在的订单号

发现并没有返回我们想要的信息

检查代码,发现我们少了配置

添加sentinel,因为我们使用的是alibaba微服务体系,所以我们使用sentinel来做熔断

sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性(sentinel如何使用我们后面的章节会讲到)

添加sentinel 依赖

<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
        </dependency>

yml配置文件添加feign开启sentinel的配置

feign:
  sentinel:
    enabled: true

重启user服务,再次访问接口

我们可以看到order服务抛了订单号不存在的异常

但是我们的接口成功返回了容错接口定义的信息

到这里feign的简单使用已经全部结束了

创作不易,点个赞吧👍

最后的最后送大家一句话

白驹过隙,沧海桑田

与君共勉

上一篇文章

springcloud alibaba微服务 – nacos使用以及注册中心和配置中心的应用(保姆级)

下一篇文章

springcloud alibaba微服务 – sentinel的使用(保姆级)

文末送福利啦~

1、Java(SE、JVM)、算法数据结构、数据库(Mysql、redis)、Maven、Netty、RocketMq、Zookeeper、多线程、IO、SSM、Git、Linux、Docker、Web前端相关学习笔记
2、2023最新BATJ大厂面试题集
3、本教程项目源码
领取方式:关注下方公主号,回复:【笔记】、【面试】、【mdx-shop】获取相关福利。

文章持续更新,可以关注下方公众号或者微信搜一搜「 最后一支迷迭香 」获取项目源码、干货笔记、面试题集,第一时间阅读,获取更完整的链路资料。

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
27天前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
51 2
|
1月前
|
JSON SpringCloudAlibaba Java
Springcloud Alibaba + jdk17+nacos 项目实践
本文基于 `Springcloud Alibaba + JDK17 + Nacos2.x` 介绍了一个微服务项目的搭建过程,包括项目依赖、配置文件、开发实践中的新特性(如文本块、NPE增强、模式匹配)以及常见的问题和解决方案。通过本文,读者可以了解如何高效地搭建和开发微服务项目,并解决一些常见的开发难题。项目代码已上传至 Gitee,欢迎交流学习。
125 1
Springcloud Alibaba + jdk17+nacos 项目实践
|
22天前
|
消息中间件 自然语言处理 Java
知识科普:Spring Cloud Alibaba基本介绍
知识科普:Spring Cloud Alibaba基本介绍
55 2
|
30天前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
27天前
|
JSON Java 数据格式
【微服务】SpringCloud之Feign远程调用
本文介绍了使用Feign作为HTTP客户端替代RestTemplate进行远程调用的优势及具体使用方法。Feign通过声明式接口简化了HTTP请求的发送,提高了代码的可读性和维护性。文章详细描述了Feign的搭建步骤,包括引入依赖、添加注解、编写FeignClient接口和调用代码,并提供了自定义配置的示例,如修改日志级别等。
71 1
|
30天前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
1月前
|
负载均衡 算法 Nacos
SpringCloud 微服务nacos和eureka
SpringCloud 微服务nacos和eureka
59 0
|
2月前
|
SpringCloudAlibaba API 开发者
新版-SpringCloud+SpringCloud Alibaba
新版-SpringCloud+SpringCloud Alibaba
|
3月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
定时任务在企业应用中至关重要,常用于异步数据处理、自动化运维等场景。在单体应用中,利用Java的`java.util.Timer`或Spring的`@Scheduled`即可轻松实现。然而,进入微服务架构后,任务可能因多节点并发执行而重复。Spring Cloud Alibaba为此发布了Scheduling模块,提供轻量级、高可用的分布式定时任务解决方案,支持防重复执行、分片运行等功能,并可通过`spring-cloud-starter-alibaba-schedulerx`快速集成。用户可选择基于阿里云SchedulerX托管服务或采用本地开源方案(如ShedLock)
122 1
|
2月前
|
人工智能 前端开发 Java
Spring Cloud Alibaba AI,阿里AI这不得玩一下
🏀闪亮主角: 大家好,我是JavaDog程序狗。今天分享Spring Cloud Alibaba AI,基于Spring AI并提供阿里云通义大模型的Java AI应用。本狗用SpringBoot+uniapp+uview2对接Spring Cloud Alibaba AI,带你打造聊天小AI。 📘故事背景: 🎁获取源码: 关注公众号“JavaDog程序狗”,发送“alibaba-ai”即可获取源码。 🎯主要目标:
83 0