1. 问题引入
在前面写的代码中,通过使用RestTemplate
来实现远程调用,但是这种方式还是存在一些问题
- 需要拼接 URL,灵活性高,但是 URL 复杂时容易写错
- 代码可读性差
而 OpenFeign 就解决了上述问题,OpenFeign 是一个声明式的 Web Service 客户端,用于简化在 Java 应用程序中调用 RESTful 服务的过程,也就是可以使用接口和注解来定义和调用 RESTful 服务,而不是手动编写 HTTP 请求代码。这种方式使得代码更简洁、易读,易于维护。
2. OpenFeign 的使用
首先,由于是 order-service 进行远程调用 product-service,需要在 order-service 中引入 openfeign 的依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
然后需要在 order-service 的启动类上添加@EnableFeignClients
注解,开启 OpenFeign 的功能
@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class,args);}
}
然后来定义一个 Feign 客户端接口:
@FeignClient(value = "product-service",path = "/product")
public interface ProductApi {@RequestMapping("/{productId}")ProductInfo getProductById(@PathVariable("productId") Integer productId);
}
通过@FeignClient
注解来定义对远程服务的调用,value 指的是要调用的服务名称,path 指的是 Feign客户端 的统一路径
接着就可以通过之前的方式来注入,再调用方法
这样就完成了远程调用
3. 参数传递
在上面的代码中,演示的是从 URL 中获取参数,接下来演示 Feign 传递参数的方式
传递单个参数和传递多个参数都是通过@RequestParam
来进行参数绑定
@RequestMapping("/p1")
String product1(@RequestParam("id") Integer id);@RequestMapping("/p2")
String product2(@RequestParam("id") Integer id,@RequestParam("name") String name);
传递对象是通过@SpringQueryMap
注解来把对象作为多个参数传递的
@RequestMapping("/p3")
String product3(@SpringQueryMap ProductInfo productInfo);
传递 JSON 还是用的@RequestBody
注解来实现的
@RequestMapping("/p4")
String product4(@RequestBody ProductInfo productInfo);
4. 最佳实践
从上面的代码中可以看出,Feign 客户端和服务提供者的 controller 代码非常相似,可以通过下面的这两种方式进行简化
4.1. 继承方式
上面是官方给出的继承的方式,来看具体怎么实现:
接口可以放在一个公共的 jar 包中,这样服务提供方和客户端都能够使用
然后把公共实体类和要被继承的接口都写在模块中
然后把当前模块打成 jar包,
让 order-service 和 product-service 分别去引入 jar 包
然后让服务提供方的 controller 实现 ProductInterface:
服务消费方去继承该接口
4.2. 抽取方式
首先还是把 Feign 的 Client 抽取为一个独立的模块,并把涉及到的实体类等都放在这个模块中,然后打成 jar 包,服务消费方只需要引入依赖即可
抽取的部分和上面还是一样的
引入依赖之后就可以直接调用,不用再写继承了,只需要在启动类上添加扫描路径,有两种方式可以添加扫描路径,一种是使用 basePackages 直接指定要扫描的路径,另一种是通过 clients 来指定具体的客户端接口类
@EnableFeignClients(basePackages = "com.example.feignclients")
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}
@EnableFeignClients(clients = {ProductApi.class})
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class,args);}
}
之后就可以成功调用了
5. 部署
由于项目中引用的是一个本地的依赖,所以打包的配置和之前又有些不一样了,首先需要指明需要从本地获取 jar 包
在 order-service 中引入依赖时指定一下要获取的 jar 包的路径
在插件中也配置一下,表示包含系统范围的依赖
之后就可以打包上传了