声明式服务调用:Spring Cloud Feign —— 继承特性

版权声明:本文为博主原创文章,转载需标明出处哦 ^-^。 https://blog.csdn.net/qq_33101675/article/details/89056346

github:https://github.com/Maple521/springcloud/tree/master/eureka-producer-%E7%BB%A7%E6%89%BF%E7%89%B9%E6%80%A7

github:https://github.com/Maple521/springcloud/tree/master/feign-consumer-%E7%BB%A7%E6%89%BF%E7%89%B9%E6%80%A7

github:https://github.com/Maple521/springcloud/tree/master/hello-service-api-%E7%BB%A7%E6%89%BF%E7%89%B9%E6%80%A7

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

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

(2)由于在hello-service-api中需要定义可同时复用于服务端于客户端的接口,我们要使用到Spring MVC的注解,所以在pom.xml中引入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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.helloserviceapi</groupId>
    <artifactId>hello-service-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hello-service-api</name>
    <description>Demo project for hello-service-api</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

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

(4)在hello-service-api工程中创建HelloService接口,内容如下:

package com.helloserviceapi.service;

import com.helloserviceapi.dto.User;
import org.springframework.web.bind.annotation.*;

@RequestMapping("/refactor")
public interface HelloService {

    @RequestMapping(value = "/hello4", method = RequestMethod.GET)
    String hello(@RequestParam("name") String name);

    @RequestMapping(value = "/hello5", method = RequestMethod.GET)
    public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);

    @RequestMapping(value = "/hello6", method = RequestMethod.POST)
    public String hello(@RequestBody User user);
}

因为后续还会通过之前的hello-service和feign-consumer来重构,所以为了避免接口混淆,在这里定义HelloService时,除了头部定义了/refactor前缀之外,同事将提供服务的三个接口更名为/hello4、/hello5、/hello6。对hello-service-api进行install,让其在本地生成一个hello-service-api-0.0.1-SNAPSHOT.jar。

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

        <dependency>
            <groupId>com.helloserviceapi</groupId>
            <artifactId>hello-service-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

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

package com.maple.eurekaproducer.controller;

import com.helloserviceapi.dto.User;
import com.helloserviceapi.service.HelloService;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@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接口类就大功告成了。

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

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

package com.feign.feignconsumer.service;

import com.feign.feignconsumer.model.User;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient("hello-service")
public interface RefactorHelloService extends HelloService{

}

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

package com.feign.feignconsumer.controller;

import com.feign.feignconsumer.service.RefactorHelloService;
import com.helloserviceapi.dto.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConsumerController {

    @Autowired
    RefactorHelloService refactorHelloService;

    @RequestMapping(value = "/feign-consumer3", method = RequestMethod.GET)
    public String helloConsumer3() {
        StringBuilder sb = new StringBuilder();
        sb.append(refactorHelloService.hello("whb")).append("\n");
        sb.append(refactorHelloService.hello("whb", 20)).append("\n");
        sb.append(refactorHelloService.hello(new User("whb", 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,调用成功后可以获得如下输出:

优点与缺点

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

猜你喜欢

转载自blog.csdn.net/qq_33101675/article/details/89056346