Feign接口继承抽离出公共方法,如何实现将服务端的公共代码抽离出来

使用feign接口时遇到的问题

现在有三个应用,消费端,服务端,接口端

API端

@RequestMapping("/shop-member")
public interface LibrarianApi{
    @RequestMapping(value = "/getByName", method = RequestMethod.GET)
    public Result<ShopMemberDTO> getByName(@RequestParam("name") String name);
}

消费端

@FeignClient(name = "librarian")
public interface ShopMemberApi extends ShopMemberLibrarianApi{
}

服务端

@RestController
public class ShopMemberNewController implements ShopMemberLibrarianApi {

}
  • 服务端和消费端都实现继承了API端的接口,在API端定义了请求路径,上述情况下分别启动应用,消费端调用正常。

  • 现在想将服务端的部分代码抽离出来,改成下面的形式

@RestController
public class ShopMemberNewController extends BaseController<ShopMemberDTO>  implements ShopMemberLibrarianApi {

}

BaseController中是抽离的公共方法,可是现在消费端无法找到服务端的接口
,404错误。

技术需求点:
在SpringCloud部署的微服务系统中,消费者通过Feign组件调用提供者的微服务。
一.Feign简介
在前文SpringCloud+SpringBoot搭建服务注册与调用平台中,我们使用了Ribbon客户端实现了微服务之间的调用,Ribbon本身集成了负载均衡的功能,但是Ribbon有一个使用不便的地方:每次使用需要手动拼接请求的url,还要对返回的结果进行格式化处理。为了解决这个不便,SpringCloud提供了一个声明式的调用组件:Feign,它可以帮助我们便捷的调用注册在注册中心的微服务。
Feign是一种声明式调用组件,提供了一种基于接口的编程方式,我们只要声明接口并配置注解,SpringCloud会根据配置以Rest风格的方式从其它微服务系统中调用方法并获取数据。
主要有以下几个优点:
(1)可插拔的注解支持,包括Feign注解和JAX-RS注解;
(2)支持可插拔的HTTP编码器和解码器;
(3)支持Hystrix和它的Fallback;
(4)支持Ribbon的负载均衡,如果某个微服务id下有两个端口提供2个同样的服务,会采用轮询机制调用;
(5)支持HTTP请求和相应的压缩。
https://segmentfault.com/a/1190000019685780?utm_source=tag-newest
二.工程搭建
在之前的文章中,我们已经搭建好了基于Springcloud + SpringBoot的工程结构:springcloud-eureka-server、springcloud-eureka-provider、springcloud-eureka-consumer等角色,这次只需要在springcloud-eureka-provider中将Ribbon组件调用的方式改成Feign即可。
1.pom文件中添加Feign依赖

org.springframework.cloud
spring-cloud-starter-openfeign

我之前使用的版本:Spring Boot版本:1.5.3.RELEASE,Spring Cloud版本:Dalston.SR5。
添加feign的pom依赖之后,发现找不到用于负载均衡的LoadBalancedRetryFactory的包,上网查资料发现是SprongBoot和SpringCloud的版本问题,不是所有SpringBoot和SpringCloud的包都是兼容的,两者的版本必须匹配使用,官网上两者匹配的版本如下:

image.png

因此,我们项目中SpringBoot版本改为用:2.0.3.RELEASE,SpringCloud的版本改为用:Finchley.RELEASE,改动代码如下:

org.springframework.boot
spring-boot-starter-parent
2.0.3.RELEASE

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2.目录结构

image.png
3.创建UserFeignService接口
Feign只需要写一个接口,在接口配置好需要调用的微服务id,并声明接口即可。如代码所示,使用注解@FeignClient,"eureka-provider"是提供者的serviceid,在整个微服务系统中是唯一的,表明该接口将调用eureka-provider的服务。方法名称和返回类型直接copy被调用服务的方法即可。
//开启feign客户端,eureka-provider-user微服务的serviceid(唯一)
@FeignClient("eureka-provider")
public interface UserFeignService {
@RequestMapping("/user")
public List getUsers();
}

@RequestMapping要写完整路径。我们这里路径比较简单,直接是"/user",如果原服务的路径是下面这种,就需要写成"/provider/user"

image.png
4.修改启动类
启动类上添加@EnableFeignClients开启Feign客户端。
@EnableFeignClients//开启Feign客户端
@EnableEurekaClient//开启Eureka客户端
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class,args);
}
}

三.测试结果
依次启动springcloud-eureka-server(集群)、springcloud-eureka-provider、springcloud-eureka-consumer服务,启动成功后,查看控制台http://192.168.33.100:8761

image.png
输入http://127.0.0.1:9091/consumer,看到下列返回说明调用成功!

image.png

四.扩展
Feign还有另外一种继承与实现的使用方式,大概做法是抽离出一个公共API项目,写一个接口让消费者继承,实现方法在提供者中实现,调用该公共接口的方法即可。
这种做法的好处是创建了独立的api项目,可以很方便的实现接口定义和依赖共享,不用再复制粘贴接口,但弊端是增加了服务提供者和消费者之间的耦合,如果服务提供者修改了一个接口定义,消费者也得跟着变,进而带来一些坑。
有兴趣的同学可以参考:https://www.jianshu.com/p/ff79509b0962

作者:superxcp
链接:https://www.jianshu.com/p/df5aa32f42a0
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。