随着微服务架构的普及服务间远程调用成为开发常态。相比于繁琐的 RestTemplate 手动调用方式OpenFeign 以声明式接口调用、简洁易用的特性成为 Spring Cloud 生态中跨服务通信的主流方案。最佳实践指的是根据历史的迭代在项目实践过程中总结出来最好的方式。其中我们总结出来两种方案继承方式和抽方式开始了解之前前提提要这次我们将以一个简单的模拟电商父子工程项目来进行演示最佳实现其中此项目包含三个模块order-service客户端、product-service服务器 和 product-api当服务启动时order-service 和 product-service 对应的服务会被注册到 nacos 上然后 order-service 通过OpenFeign 对 product-service 模块发起服务调用此外还添加多了一个 product-api 模块用于后续的演示下图是关系图1.1Feign继承方式这个所谓的继承就是想通过减少多余的代码让外部的接口继承给想继承的模块鉴于此若我们想创建一个接口的话既不能将具体方法同步给客户端以免代码冗余又不能将web服务给其他第三方程序引入所以这次就是将product-api这个api继承到product-service这个服务里面。1.1.1操作方法首先当我们做好前期的准备工作后将用到的实体类productInfo和productInterface创建好后我们就把这个打包成一个jar包放到maven仓库让product-service和order-service这两个模块后续通过pom文件引入依赖来获得这个apidependency groupIdcom.bit.demo/groupId artifactIdproduct-api/artifactId version1.0-SNAPSHOT/version scopecompile/scope /dependency当引入完之后就是一系列的进行继承让原来的模块继承这个新的apiProduct-servicepackage com.bite.product.controller; import com.bite.product.api.ProductInterface; import com.bite.product.model.ProductInfo; import com.bite.product.service.ProductService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; Slf4j RestController RequestMapping(/product) public class ProductController implements ProductInterface { Autowired private ProductService productService; RequestMapping(/{productId}) public ProductInfo getProductInfo(PathVariable(productId) Integer productId) { log.info(接收到参数productId,productId); return productService.selectProductById(productId); } RequestMapping(/p1) public String p1(Integer id){ return product-service 接收到一个参数id id; } RequestMapping(/p2) public String p2(Integer id, String name){ return product-service 接收到一个参数id id name: name; } RequestMapping(/p3) public String p3(ProductInfo productInfo){ return product-service 接收到一个参数productInfo productInfo.toString(); } RequestMapping(/p4) public String p4(RequestBody ProductInfo productInfo){ return product-service 接收到一个参数productInfo productInfo.toString(); } }Order-servicepackage com.bite.order.api; import org.springframework.cloud.openfeign.FeignClient; FeignClient(value product-service,path product) public interface ProductInterface extends com.bite.product.api.ProductInterface { }当我们搞完后这个些进行测试发现是成功的1.2Feign抽取方式这个相较于上面的继承方式它的重点更多是偏向将接口抽取成为一个独立的模块与继承类似但不同的是他这个可以减去Order-service的Feign接口声明因此我们此次的product-api模块里面放置的是提取出来的公共代码像这次的order-service这里面的product-api、product-service的productInfo我们就把他提取到这个模块里面接着就是和上面一样的打包到仓库导入依赖到需要调用的模块的操作但这里可能会出现一个问题就是idea会报错说ProductApi这个类没有被扫到那是因为spring启动的时候默认只扫描当前的启动类所在的目录但由于这个ProductApi不在这里所以就报错。1.2.1解决外部类无法被spring扫描的问题为了解决这个问题官方提供了EnableFeignClients这个注解其中有包含了两种解决方案。其一就是通过basePakage这个指定扫描的路径其二就是使用client这个方式引入第三方的一个Feign声明package com.bite.order; import com.bite.product.api.ProductApi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; EnableFeignClients(clients {ProductApi.class}) SpringBootApplication public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class,args); } }经过调整后测试也是成功的1.3总结因此综上所述当我们想要方便简单代码少的话就使用继承的方法但是缺点是不能耦合性高跨微服务不能使用。当我们抽取公共SDK或者是远程调用的话我们就能使用抽取的方案https://gitee.com/mount-everest-g20/best_-practices_for_-microservices这里是两个学习项目的码云地址感兴趣的可以下载到本地看下本期就到这啦欢迎下次再见