SpringCloud - 声明式服务调用组件Feign使用详解3(继承特性)
从之前文章的样例中可以发现,当使用 Spring MVC 的注解来绑定服务接口时,我们几乎完全可以从服务提供方的 Conroller 中依靠复制操作,构建出相应的服务客户端绑定接口。但每次都要进行这些复制操作略显麻烦。
(3)编写实体类 User:
(4)编写 HelloService 接口:
(5)使用 maven 命令 install 在本地仓库创建 jar 包:

(2)创建 HelloController 类继承 hello-service-api 中定义的 HelloService 接口,并实现这三个接口:
(2)创建 RefactorHelloService 接口并继承 hello-service-api 中定义的 HelloService 接口,然后添加 @FeignClient 注解来绑定服务即可:
(3)最后在 ConsumerController 中,注入 RefactorHelloService 实例并调用即可:

在 Spring Cloud Feign 中,针对该问题提供了继承特性来帮助我们解决这些复制操作,以进一步减少编码量。下面通过样例演示如何通过 Spring Cloud Feign 的继承特性来实现 REST 接口定义的复用。
三、继承特性
1,创建基础 Maven 工程
(1)为了能够复用 DTO 与接口定义,我们创建一个基础的 Maven 工程,命名为 hello-service-api:

(2)编写 pom.xml 文件,由于我们要使用到 Spring MVC 的注解,所以需要引入 spring-boot-starter-web 依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hangge</groupId> <artifactId>hello-service-api</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>hello-service-api</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.6</version> </dependency> </dependencies> </project>
(3)编写实体类 User:
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @ToString public class User { private String name; private Integer age; }
(4)编写 HelloService 接口:
@RequestMapping("/refactor") public interface HelloService { // 带有Request参数的请求 @GetMapping("/hello1") String hello1(@RequestParam("name") String name) ; // 带有Header信息的请求 @GetMapping("/hello2") User hello2(@RequestHeader("name") String name, @RequestHeader("age") Integer age); // 带有Header信息的请求 @PostMapping("/hello3") String hello3(@RequestBody User user); }
(5)使用 maven 命令 install 在本地仓库创建 jar 包:

(6)去本地仓库查看下发现确实已经创建成功了:

2,改造服务提供者
(1)首先编辑 hello-service 的 pom.xml 文件,新增对 hello-service-api 的依赖:
<dependency> <groupId>com.hangge</groupId> <artifactId>hello-service-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
(2)创建 HelloController 类继承 hello-service-api 中定义的 HelloService 接口,并实现这三个接口:
- 在这个类中,除了要实现逻辑接口外,只需要增加 @RestController 注解使该类成为一个 REST 接口类就大功告成了。
- 而且通过继承的方式,在 Controller 中不再包含以往会定义的请求映射注解(如:@RequestMapping、@GetMapping、@PostMapping),而参数的注解定义在重写的时候就会自动带过来。
@RestController public class HelloController implements HelloService { // 带有Request参数的请求 @Override public String hello1(@RequestParam String name) { return "hello1 " + name; } // 带有Header信息的请求 @Override public User hello2(@RequestHeader String name, @RequestHeader Integer age) { return new User(name, age); } // 带有Header信息的请求 @Override public String hello3(@RequestBody User user) { return "hello3 " + user.getName() + ", " + user.getAge(); } }
3,改造服务消费者
(1)首先编辑 feign-consumer 的 pom.xml 文件,同样新增对 hello-service-api 的依赖:
<dependency> <groupId>com.hangge</groupId> <artifactId>hello-service-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
(2)创建 RefactorHelloService 接口并继承 hello-service-api 中定义的 HelloService 接口,然后添加 @FeignClient 注解来绑定服务即可:
@FeignClient("hello-service") public interface RefactorHelloService extends HelloService { }
@RestController public class ConsumerController { @Autowired RefactorHelloService refactorHelloService; @GetMapping(value = "/feign-consumer") public String helloConsumer() { String result1 = refactorHelloService.hello1("hangge1"); User result2 = refactorHelloService.hello2("hangge2", 100); String result3 = refactorHelloService.hello3(new User("hangge3",0)); return result1 + "<br>" + result2 + "<br>" +result3; } }
4,验证测试
我们启动服务中心、HELLO-SERVICE、FEIGN-CONSUMER,访问 http://localhost:9001/feign-consumer 触发对 HELLO-SERVICE 接口的调用,最终会获得如下输出,代表接口绑定和调用成功。
附:使用继承特性的优缺点
1,优点
可以将接口的定义从 Controller 中剥离,同时配合 Maven 私有仓库就可以轻易地实现接口定义的共享,不用再复制粘贴接口进行绑定,而是实现在构建期的接口绑定,从而有效减少服务客户端的绑定配置。2,缺点
由于接口在构建期间就建立起了依赖,那么接口变动就会对项目构建造成影响,可能服务提供方修改了一个接口定义,那么会直接导致客户端工程的构建失败。 所以,如果开发团队通过此方法来实现接口共享的话,建议在开发评审期间严格遵守面向对象的开闭原则,尽可能地做好前后版本的兼容,防止牵一发而动全身的后果,增加团队不必要的维护工作量。