当前位置: > > > SpringCloud - 声明式服务调用组件Feign使用详解3(继承特性)

SpringCloud - 声明式服务调用组件Feign使用详解3(继承特性)

    从之前文章的样例中可以发现,当使用 Spring MVC 的注解来绑定服务接口时,我们几乎完全可以从服务提供方的 Conroller 中依靠复制操作,构建出相应的服务客户端绑定接口。但每次都要进行这些复制操作略显麻烦。
    在 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-servicepom.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 {
}

(3)最后在 ConsumerController 中,注入 RefactorHelloService 实例并调用即可:
@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-SERVICEFEIGN-CONSUMER,访问 http://localhost:9001/feign-consumer 触发对 HELLO-SERVICE 接口的调用,最终会获得如下输出,代表接口绑定和调用成功。

附:使用继承特性的优缺点

1,优点

    可以将接口的定义从 Controller 中剥离,同时配合 Maven 私有仓库就可以轻易地实现接口定义的共享,不用再复制粘贴接口进行绑定,而是实现在构建期的接口绑定,从而有效减少服务客户端的绑定配置。

2,缺点

    由于接口在构建期间就建立起了依赖,那么接口变动就会对项目构建造成影响,可能服务提供方修改了一个接口定义,那么会直接导致客户端工程的构建失败。
    所以,如果开发团队通过此方法来实现接口共享的话,建议在开发评审期间严格遵守面向对象的开闭原则,尽可能地做好前后版本的兼容,防止牵一发而动全身的后果,增加团队不必要的维护工作量。
评论0