返回介绍

继承特性

发布于 2024-08-18 11:12:34 字数 5840 浏览 0 评论 0 收藏 0

通过“快速入门”以及“参数绑定”小节中的示例实践,相信很多读者已经观察到,当使用 Spring MVC 的注解来绑定服务接口时,我们几乎完全可以从服务提供方的Controller中依靠复制操作,构建出相应的服务客户端绑定接口。既然存在这么多复制操作,我们自然需要考虑这部分内容是否可以得到进一步的抽象呢?在Spring Cloud Feign中,针对该问题提供了继承特性来帮助我们解决这些复制操作,以进一步减少编码量。下面,我们详细看看如何通过Spring Cloud Feign的继承特性来实现REST接口定义的复用。

- 为了能够复用 DTO 与接口定义,我们先创建一个基础的 Maven 工程,命名为hello-service-api。

- 由于在 hello-service-api 中需要定义可同时复用于服务端与客户端的接口,我们要使用到 Spring MVC 的注解,所以在 pom.xml 中引入 spring-bootstarter-web依赖,具体内容如下所示:

<groupId>com.didispace</groupId>

<artifactId>hello-service-api</artifactId>

<version>0.0.1-SNAPSHOT</version>

<packaging>jar</packaging>

<name>hello-service-api</name>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>1.3.7.RELEASE</version>

<relativePath/> <!--lookup parent from repository-->

</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>

</dependencies>

- 将上一节中实现的 User 对象复制到 hello-service-api 工程中,比如保存到com.didispace.dto.User。

- 在hello-service-api工程中创建com.didispace.service.HelloService接口,内容如下,该接口中的User对象为本项目中的com.didispace.dto.User。

- 将上一节中实现的 User 对象复制到 com.didispace.dto.User。创建com.didispace.service.HelloService 接口,内容如下,该接口中的 User对象为本项目中的com.didispace.dto.User。

@RequestMapping("/refactor")

public interface HelloService {

@RequestMapping(value="/hello4",method=RequestMethod.GET)

String hello(@RequestParam("name")String name);

@RequestMapping(value="/hello5",method=RequestMethod.GET)

User hello(@RequestHeader("name")String name,@RequestHeader("age")Integer age);

@RequestMapping(value="/hello6",method=RequestMethod.POST)

String hello(@RequestBody User user);

}

因为后续还会通过之前的hello-service和feign-consumer来重构,所以为了避免接口混淆,在这里定义HelloService时,除了头部定义了/rafactor前缀之外,同时将提供服务的三个接口更名为/hello4、/hello5、/hello6。

- 下面对 hello-service 进行重构,在 pom.xml 的 dependency 节点中,新增对hello-service-api的依赖。

<dependency>

<groupId>com.didispace</groupId>

<artifactId>hello-service-api</artifactId>

<version>0.0.1-SNAPSHOT</version>

</dependency>

- 创建 RefactorHelloController 类继承 hello-service-api 中定义的HelloService接口,并参考之前的HelloController来实现这三个接口,具体内容如下所示:

@RestController

public class RefactorHelloController implements HelloService {

@Override

public String hello(@RequestParam("name")String name){

return "Hello "+name;

}

@Override

public User hello(@RequestHeader("name")String name,@RequestHeader("age")Integer age){

return new User(name,age);

}

@Override

public String hello(@RequestBody User user){

return "Hello "+user.getName()+","+user.getAge();

}

}

我们可以看到通过继承的方式,在 Controller 中不再包含以往会定义的请求映射注解@RequestMapping,而参数的注解定义在重写的时候会自动带过来。在这个类中,除了要实现接口逻辑之外,只需再增加@RestController注解使该类成为一个REST接口类就大功告成了。

- 完成了服务提供者的重构,接下来在服务消费者 feign-consumer 的 pom.xml文件中,如在服务提供者中一样,新增对hello-service-api的依赖。

- 创建 RefactorHelloService 接口,并继承 hello-service-api 包中的HelloService接口,然后添加@FeignClient注解来绑定服务。

@FeignClient(value="HELLO-SERVICE")

public interface RefactorHelloService extends com.didispace.service.HelloService {

}

- 最后,在ConsumerController中,注入RefactorHelloService的实例,并新增一个请求/feign-consumer3来触发对RefactorHelloService的实例的调用。

@Autowired

RefactorHelloService refactorHelloService;

@RequestMapping(value="/feign-consumer3",method=RequestMethod.GET)

public String helloConsumer3(){

StringBuilder sb=new StringBuilder();

sb.append(refactorHelloService.hello("MIMI")).append("\n");

sb.append(refactorHelloService.hello("MIMI",20)).append("\n");

sb.append(refactorHelloService.hello(new com.didispace.dto.User("MIMI",20))).append("\n");

return sb.toString();

}

测试验证

这次的验证过程需要注意几个工程的构建顺序,由于 hello-service 和feign-consumer都依赖hello-service-api工程中的接口和DTO定义,所以必须先构建hello-service-api工程,然后再构建hello-service和feign-consumer。接着我们分别启动服务注册中心,hello-service 和 feign-consumer,并访问http://localhost:9001/feign-consumer3,调用成功后可以获得如下输出:

Hello MIMI

name=MIMI,age=20

Hello MIMI,20

优点与缺点

使用Spring Cloud Feign继承特性的优点很明显,可以将接口的定义从Controller中剥离,同时配合Maven私有仓库就可以轻易地实现接口定义的共享,实现在构建期的接口绑定,从而有效减少服务客户端的绑定配置。这么做虽然可以很方便地实现接口定义和依赖的共享,不用再复制粘贴接口进行绑定,但是这样的做法使用不当的话会带来副作用。由于接口在构建期间就建立起了依赖,那么接口变动就会对项目构建造成影响,可能服务提供方修改了一个接口定义,那么会直接导致客户端工程的构建失败。所以,如果开发团队通过此方法来实现接口共享的话,建议在开发评审期间严格遵守面向对象的开闭原则,尽可能地做好前后版本的兼容,防止牵一发而动全身的后果,增加团队不必要的维护工作量。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文