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

相关推荐
EatFan8 小时前
Java接入支付宝 JSAPI 支付保姆教程(二):流程讲解与前后端代码讲解
前端·spring boot·后端·微信小程序·小程序·uni-app
步行cgn9 小时前
Spring 启动报错:BeanFactory not initialized 的原因与解决
java·python·spring
步行cgn9 小时前
Spring 报错:No bean class specified on bean definition 的原因与解决
java·后端·spring
凤山老林9 小时前
Spring Boot 整合 Flowable 的企业级落地指南
数据库·spring boot·后端·flowable·工作流
重生之我是Java开发战士10 小时前
【Spring Cloud】Nacos注册中心
后端·spring·spring cloud
Wang's Blog10 小时前
Java框架快速入门:Spring Security+OAuth2之用户注册与唯一性校验实现
java·数据库·spring
Wang's Blog10 小时前
Java框架快速入门: Spring Security+OAuth2之多因子认证与TOTP实战
java·spring·ui
代码调试师11 小时前
【毕设分享】基于SpringBoot的旅游向导分配管理系统57145
spring boot·毕业设计·源码·课程设计·毕设·大作业·程序定制
2301_322414280412 小时前
活力孕康复APP 47737- 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·mysql·微信小程序·idea·微信开发者工具
vx_Biye_Design13 小时前
springboot游泳馆系统93765-计算机课程设计、毕业设计
java·javascript·spring boot·后端·python·spring·课程设计