SpringCloud---OpenFeign

(一).前言

这是我们远程调用的代码,虽然RestTemplate对HTTP封装后,已经比直接使用HTTPClient简单方便很多,但是还存在一些问题,例如,拼接URL,当URL复杂时容易出错;代码可读性差;如果传递多个参数的时候,会很麻烦。

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

在SpringCloud中,默认是使用HTTP来进行微服务的通信,最常用的实现方式形式有两种:RestTemplate和OpenFeign,下面就开始介绍OpenFeign

(二).OpenFeign介绍

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

OpenFeign的前身的Feign,Feign是Netflix公司开源的一个组件。可以简单的理解为Netflix Feign是OpenFeign的祖先,或者说OpenFeign是Netflix Feign的升级版,OpenFeign是Feign的一个更强大更灵活的实现。

Spring Cloud Feign,Spring Cloud Feign 是Spring对Feign的封装,将Feign项目集成到Spring Cloud生态系统中。这里我们使用的Spring Cloud Feign的依赖是 spring-cloud-starter-openfeign

(三).使用OpenFeign

1.引入依赖

在order-service中引入OpenFeign的依赖

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

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

在order-service的启动类上添加**@EnableFeignClients**,开启OpenFeign

java 复制代码
package org.com.spring;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication {

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

3.编写客户端

通过Spring MVC的注解来声明远程调用的信息

java 复制代码
package org.com.spring.api;


import org.com.spring.mapper.doobject.ProductDetailDO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient(name = "product-service",path = "/product")
public interface ProductApi {

    @RequestMapping("/getDetail")
    ProductDetailDO getDatail(Integer id);

}

4.修改远程调用

java 复制代码
    @Override
    public OrderDetailDTO getOrderDetail(Integer id) {
        //1.校验非空
        if (null == id || id < 0) {
            log.error("订单不存在");
        }
        //2.调用Mapper
        OrderDetailDO orderDetail = orderMapper.getOrderDetail(id);
        if (null==orderDetail){
            log.error("订单不存在");
        }

//        String url="http://product-service/product/getDetail?id="+orderDetail.getProductId();
//        ProductDetailDO productDetailDO = restTemplate.getForObject(url, ProductDetailDO.class);
        /**
         * 调用ProductApi中的接口方法
         */
        ProductDetailDO productDetailDO = productApi.getDatail(orderDetail.getProductId());

        if (null==productDetailDO){
            log.error("商品不存在");
        }

        //3.返回结果
        return convertToOrderDetailDTO(orderDetail,productDetailDO);
    }

5.启动项目进行测试

当启动的时候

发现,报错了。这是因为对于OpenFeign来说,如果要进行参数的传递,则必须使用 @RequestParam注解做参数绑定,不能省略

java 复制代码
package org.com.spring.api;


import org.com.spring.mapper.doobject.ProductDetailDO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "product-service",path = "/product")
public interface ProductApi {

    @RequestMapping("/getDetail")
    ProductDetailDO getDatail(@RequestParam("id") Integer id);

}

可以发现,测试成功了。同时也可以看出来,使用Feign也可以实现远程调用。Feign简化了与HTTP服务交互的过程,把REST客户端的定义转换成Java接口,并通过注解的方式来声明请求参数,请求方式等信息,使远程调用更加方便和简洁。

(四).OpenFeign参数传递

1.传递单个参数

服务方product-service

java 复制代码
    @RequestMapping("get1")
    public String get1(Integer id){
        return "接收一个参数:"+id;
    }

Feign客户端

java 复制代码
    @RequestMapping("get1")
    String get1(@RequestParam("id") Integer id);

服务消费方order-service

java 复制代码
    @RequestMapping("get1")
    public String get1(Integer id){
        return productApi.get1(id);
    }    

可以发现,可以成功的

2.传递多个参数

服务方product-service

java 复制代码
    @RequestMapping("get2")
    public String get2(Integer id,String name){
        return "接收多个参数,id: "+id+",name: "+name;
    }

Feign客户端

java 复制代码
    @RequestMapping("get2")
    String get2(@RequestParam("id") Integer id,@RequestParam("name") String name);

服务消费方order-service

java 复制代码
    @RequestMapping("get2")
    public String get2(Integer id,String name){
        return productApi.get2(id,name);
    }

可以发现,也是可以成功的

3.传递对象

服务方product-service

java 复制代码
    @RequestMapping("get3")
    public String get3(ProductDetailDTO productDetailDTO){
        return "接收一个对象:"+productDetailDTO.toString();
    }

Feign客户端

java 复制代码
    @RequestMapping("get3")
    String get3(@SpringQueryMap ProductDetailDTO productDetailDTO);

这里要使用@SpringQueryMap注解,进行参数的绑定

服务消费方order-service

java 复制代码
    @RequestMapping("get3")
    public String get3(ProductDetailDTO productDetailDTO){
        return productApi.get3(productDetailDTO);
    }

可以发现,也是可以成功的

4.传递JSON

服务方product-service

java 复制代码
    @RequestMapping("get4")
    public String get4(@RequestBody ProductDetailDTO productDetailDTO){
        return "接收一个JSON对象:"+productDetailDTO.toString();
    }

Feign客户端

java 复制代码
    @RequestMapping("get4")
    String get4(@RequestBody ProductDetailDTO productDetailDTO);

服务消费方order-service

java 复制代码
    @RequestMapping("get4")
    public String get4(@RequestBody ProductDetailDTO productDetailDTO){
        return productApi.get4(productDetailDTO);
    }

可以看到,也是可以测试成功的

(五).最佳实践

最佳实践,指的是,经过历史的迭代,在项目的实践过程中,总结出来的最好的使用方式。事实上,也不难发现,Feign的客户端与服务提供者的controller代码十分相似

此时,就可以引入Feign的最佳实践了。Feign的最佳实践有两种,第一种是Feign的继承方式,第二种是Feign的抽取方式

1.Feign的继承方式

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

(1).创建一个Module

这里我们定义的接口,可以放在一个公共的Jar包里,供服务提供方和服务消费方使用

(2).引入依赖

在新的Jar包中引入对应的依赖

XML 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

(3).编写接口

这里,直接将ProductApi和用到的返回值ProductDetailDO,ProductDetailDTO复制到接口中即可

(4).打Jar包

这里,打Jar包指的是,把当前这个接口工程打成Jar包,放到maven本地仓库,不是远程仓库

选择install

可以看到,已经打包成功了

(5).服务提供方

服务提供方实现接口ProductApi

注意:在实现的时候,会有很多指向性的问题,例如,返回值,接口调用等问题,统统使用新的接口中返回值和方法

(6).服务消费方

服务消费方直接继承ProductApi这个接口

(7).进行测试

可以看到,测试成功了

2.Feign的抽取方式

官方推荐Feign的使用方式为继承的方式,但是在开发中,更多是把Feign接口抽取为独立的模块,抽取的方式和继承相似,但是理念不同

(1).创建一个Module

(2).引入依赖

XML 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

(3).编写API

复制前面的ProductApi,ProductDetailDTO到product-api模块中

(4).打Jar包

还是选择install

(5).服务消费方使用

Ⅰ.将order-service中的ProductApi和ProductDTO注释到

Ⅱ.引入依赖

XML 复制代码
        <dependency>
            <groupId>org.com.spring</groupId>
            <artifactId>product-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

这个依赖是刚才打包的那个接口的依赖

Ⅲ.指定扫描类ProductApi

在启动类上添加**@EnableFeignClients**注解,如何指定扫描类为ProductApi

相关推荐
AI_小站2 小时前
刚面完百度的 Agent 开发岗,我才发现:世界就是个巨大的草台班子
java·开发语言·人工智能·spring·百度·langchain
普通网友2 小时前
Springboot中使用Elasticsearch(部署+使用+讲解 最完整)
spring boot·elasticsearch·jenkins
孙克旭_4 小时前
Docker 镜像构建|Vue+SpringBoot+Go 多语言项目 Dockerfile 案例
linux·运维·vue.js·spring boot·docker·dockerfile
2602_959960924 小时前
谢飞机面试大厂:Spring Boot、JVM、Redis、Kafka、微服务与音视频搜索场景求生实录
java·jvm·spring boot·redis·面试题
晓晓_za8986685 小时前
Geo 优化源码蒸馏词机制:地域词库构建与匹配逻辑详解
运维·tcp/ip·spring·缓存·ci/cd
ycjunhua8 小时前
Spring AI 2.0 GA:ToolCallingAdvisor 重构与 Java Agent 新范式
java·人工智能·spring
让你三行代码QAQ9 小时前
SpringAI-依赖问题
spring·ai编程
风流 少年10 小时前
Spring AI 2.0:阿里云百炼平台(智能体应用)
redis·spring·阿里云
宠友信息12 小时前
IM系统开发技术路线分析,即时通讯源码助力快速搭建聊天应用
java·spring boot·redis·websocket·mysql·uni-app·vue