优雅的实现远程调用--OpenFeign

RestTemplate存在问题:

虽然说RestTemplate对HTTP封装后,已经比直接使用HTTPClient简单方便多了,但是还是存在一些问题:

1,需要拼接URL,灵活性高,但是封装繁琐,如果URL复杂时,容易出错

2.代码可读性差,风格不统一

微服务之间的通信方式,通常有两种:RPC和HTTP

在SpringCloud中,默认是使用HTTP来进行微服务的通信,最常用的实现形式有两种:1.RestTemplate 2.OpenFeign

ps:RPC(Remote Procedure Call)远程过程调用,是一种网络从远程计算机上请求服务,而不需要了解底层网络通信细节,RPC可以使用多种网络协议进行通信,如HTTP,TCP,UDP等,并且在TCP/IP网络四层模型中跨越了传输层和应用层,简言之RPC就像调用本地方法一样调用远程方法

OpenFeign介绍

OpenFeign是一个声明式WebService客户端,他让微服务之间的调用变得更简单,类似Controller调用Service,只需要创建一个接口,然后添加注解就可以使用OpenFeign

OpenFeign的前身是Feign Feign是Netflix公司开源的一个组件

可以理解为Netflix Feign是OpenFeign的祖先,或者说OpenFeign是Netflix Feign的升级版

SpringCloudFeign

SpringCloudFeign是Spring对Feign的封装,将Feign项目集成到SpringCloud生态系统中,受Feign更名影响,SpringCloudFeign也有两个starter:1.spring-cloud-starter-feign 2.spring-cloud-starter-openfeign

OpenFeign快速上手

1.引入依赖

复制代码
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.通过注解,开启Feign的功能

在订单服务(要调用某个module)的启动类加上@EnableFeignClients的注解,表示开启OpenFeign的功能

3.编写客户端

基于SpringMVC的注解来声明远程他用的信息

java 复制代码
@FeignClient(value = "product-service")
public interface ProductAPI{
    @RequestingMapping("/product/{productId}")
    ProductInfo getProductInfo(@PathVariable("productId") Integer productId);
}

也可以使用@FeignClient(Path="/product")表示feign客户端的统一前缀

4.修改远程调用

java 复制代码
@Autowired
private ProductApi productApi;

    public OrderInfo selectOrderById(Integer orderId){
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        ProductInfo productInfo = productApi.getProductById(orderInfo.getProductId());
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }

5.进行测试

启动服务访问接口,测试远程调用会发现,使用feign也可以实现远程调用

Feign简化了与HTTP服务交互的过程,把REST客户端的定义转换为JAVA接口,并通过注解的方式来声明请求参数等信息,使远程调用更加方便

OpenFeign参数传递

1.传递单个参数

要用@RequestParam做参数绑定,这是不能忽略的

服务提供方product-service

java 复制代码
@RequestMapping("/product")
@RestController
public class ProductController{
    @RequesMapping("/p1)
    public String p1(Integer id){
        return "p1接受到参数:"+id;
    }    
}

Feign客户端

java 复制代码
@FeignClient(value="product-service",path="/product)
public interface ProductApi{
    @RequestMapping("/p1)
    String p1(@RequestParam("id")Integer id)
}

服务消费方

java 复制代码
@RequestMapping("/feign)
@RestController
public class FeignController{
    @Autowired
    private ProductApi productApi;

    @RequestMapping("o1")
    public String o1(Integer id){
        return productApi.p1(id);
    }
}

测试远程调用

2.传递多个参数

使用多个@RequestParam进行参数绑定即可

服务提供方

java 复制代码
@RequestMapping("/product")
@RestController
public class ProductController{
    @RequesMapping("/p2)
    public String p2(Integer id,String name){
        return "p2接受到参数:"+id+ " "+name;
    }    
}

Feign客户端

java 复制代码
@FeignClient(value="product-service",path="/product)
public interface ProductApi{
    @RequestMapping("/p2)
    String p2(@RequestParam("id")Integer id @RequestParam("name")String name)
}

服务消费方

java 复制代码
@RequestMapping("/feign)
@RestController
public class FeignController{
    @Autowired
    private ProductApi productApi;

    @RequestMapping("o2")
    public String o1(Integer id,String name){
        return productApi.p2(id,name);
    }
}

3,传递对象

服务提供方

java 复制代码
@RequestMapping("/product")
@RestController
public class ProductController{
    @RequesMapping("/p3)
    public String p2(ProductInfo productInfo){
        return "接受到对象,productInfo:"+productInfo;
    }    
}

Feign客户端

java 复制代码
@FeignClient(value="product-service",path="/product)
public interface ProductApi{
    @RequestMapping("/p3)
    String p3(@SpringQueryMap ProductInfo productInfo);
}

服务消费方

java 复制代码
    @RequestMapping("/o3")
    public String o3(){
        ProductInfo productInfo = new ProductInfo();
        productInfo.setId(45);
        productInfo.setProductName("T恤");
        return productApi.p3(productInfo);
    }

4.传递JSON

feign客户端在传递参数的时候加上@RequestBody即可

OpenFeign的最佳实现

1.继承

可以把一个常见的操作封装到接口里,我们定义好一个接口,服务提供实现这个接口,服务消费方编写Feign接口的时候,直接继承这个接口

2.抽取的方式

官方推荐的方式为继承的方式,但是企业开发的时候更多的是把Feign接口抽取为一个独立的模块(做法和继承相似但理念不同)

将Feign抽取为要给独立的模块,并把涉及到的实体类等都放在一个模块中,打成一个jar包,服务消费方只需要依赖该jar包即可

相关推荐
我登哥MVP1 小时前
SpringCloud 核心组件解析:服务调用和负载均衡
java·spring boot·后端·spring·spring cloud·java-ee·负载均衡
爱吃牛肉的大老虎2 小时前
SpringCloud之负载均衡 Ribbon和LoadBalancer讲解
spring cloud·ribbon·负载均衡
运维瓦工19 小时前
DevOps 生态介绍(十):Docker Compose 核心 YAML 配置详解与常用命令大全
spring cloud·docker·容器
worilb21 小时前
Spring Cloud 学习与实践(8):Spring Cloud Gateway 统一入口、路由转发与双重跨域故障演练
学习·spring·spring cloud
Devin~Y1 天前
大厂 Java 面试实战:从 Spring Boot 微服务到 AI RAG 音视频平台全链路解析
java·spring boot·redis·spring cloud·微服务·rag·spring ai
我登哥MVP1 天前
SpringCloud 核心组件解析:服务注册与发现
java·spring boot·后端·spring·spring cloud·java-ee·maven
豆瓣鸡2 天前
Spring Cloud笔记
spring·spring cloud
百珏2 天前
流量没暴涨,网关却挂了:Spring Cloud Gateway 从 500 QPS 优化到 4200 QPS
后端·spring cloud·架构
小小放舟、3 天前
@JsonCreator 注解详解——从枚举反序列化说起
spring boot·spring·spring cloud·java-ee·maven·intellij-idea·状态模式