https://github.com/yinjihuan/kitty-cloud
Kitty Cloud 开源后有以为朋友在 GitHub 上给我提了一个 issues,问为什么项目中要同时集成 Feign 和 Dubbo 两个框架来调用服务。今天就来聊一聊这个问题,然后讲下在 Kitty Cloud 中如何切换使用两种调用方式。
关于支持两种协议,我这个是一个开源项目,主要还是为了让使用者有更多的选择。当然框架本身不是我开发的,我只是使用者而已。
一种协议更统一化,两种协议混着用也不是不可以,具体还是看实际需求。比如你们内部有个 ID 分发的服务,调用量很高,就是对性能有这极致的要求。那么这个场景你就可以用 Rpc 来代替 Http 了。其他的正常使用 Http 协议就行,特殊场景的就用 Rpc 协议,互补而已。
用 Http 最好的点在于简单,传输内容就是文本,调试什么的都很方便。比如我要单独测试某个服务的接口,直接 PostMan 上调用这个 Http 接口就可以了,或者用 Swagger。
如果是 Dubbo 的 Rpc, 我可能需要用 telnet 来调用。
还有就是网关层的转发,如果是 Http 协议,直接转发过去了。如果是 Rpc 协议,网关内部需要转特殊处理,当然目前也有支持 Rpc 的网关。如果我们是两种协议,网关这边还是直接 Http 转发过去即可,内部服务之前想用什么协议让使用者自己决定。
其实在 Spring Cloud 慢慢进入企业后,有很多人都会遇到一个问题就是老的服务都是用 Dubbo 来通信的,如果转 Spring Cloud 技术栈,那么势必要去掉 Dubbo。
如果规模不大直接重构掉也没关系,但是对于大规模的应用,服务数量众多。不太可能一口吃成个胖子。就算要重构那也是一个一个的方式来,也就意味着在没重构完之前,老的服务还是 Dubbo,但有一些服务已经变成 Spring Cloud 体系了。这个时候兼容就是一个迫切需要解决的问题。
Spring Cloud Alibaba 的出现就为这个问题提供了完美的解决方案,同时支持两种协议,可以慢慢过渡迁移。
下面通过一个例子来说明:
下图中有两个服务,最开始都是 Rpc 协议,服务 A 通过 Rpc 方式调用服务 B。
当我们将服务 B 重构成 Http 协议后,服务 A 就需要使用 Http 方式来调用服务 B。
如果从实现需求上来讲,很简单,将服务 A 中调用的代码给出用 Feign 或者 RestTemplate 调用即可。但是这样也就意味着我重构了 B 服务,还需要改动 A 服务的代码,很有可能不止 A 一个服务在调用 B 服务,也许有几十个,那么我是不是得改几十个服务的调用方式。
显然这个方案不可行。你如果这样出方案,你老大一个眼神送给你,自己体会吧。。。。。
方案一既然被否了,那需求很明显嘛,就是你可以重构成 Spring Cloud 技术栈,但是你不能影响使用方。
要想不影响使用方,感觉只能从 Dubbo 的调用这块入手。也就是在 Dubbo 底层去扩展 ,如果目标服务是老的 Rpc 协议,那么调用方式保持不变即可。
如果目标服务变成新的 Http 协议,那么就需要使用新的方式去调用,只有在底层兼容了才不会影响使用方。
第三种方案也就是我们现在目前的方案,让服务 B 支持双协议,支持双协议后,那么所有的调用方都不用改变,因为 Rpc 的方式还支持。如果有新的服务可以使用 Http 来调用 B 服务的接口。
支持两种协议的核心在于 Dubbo Spring Cloud ,Dubbo Spring Cloud 作为 Spring Cloud Alibaba 中的最核心组件,基本上适配了 Spring Cloud 技术栈。
接口还是单独抽出来放在 API 模块中,FeignClient 相关定义在接口上。
在实现类中同时暴露两种协议,加上 Dubbo 的@Service 和@RestController 注解。
使用方只需要注入接口即可调用,如果想使用 Feign 调用就用@Autowired 进行注入。
@Autowired private UserRemoteService userRemoteService;
如果想使用 Dubbo 进行调用就用@Reference 进行注入。
@Reference(version = DubboConstant.VERSION_V100, group = DubboConstant.DEFAULT_GROUP, check = false) private UserRemoteService userRemoteService;
还有一个很重要的配置在于需要将 Dubbo 的注册中心挂载到 Spring Cloud 注册中心上。
dubbo.registry.address=spring-cloud://localhost
目前虽然支持了双协议,但使用权交到了用户手里。就是你想用什么协议发起调用都可以,是通过硬编码的方式来处理的。
如果想灵活度更高的话,我们可以在 Dubbo 或者 Feign 的底层去扩展。比如基于 Feign 去扩展的话,那就是调用都是采用 Feign 的方式,不需要用@Reference 来注入客户端。我们可以通过集成配置中心,用配置的方式来指定采用哪种协议调用。在 Feign 底层通过配置内容决定是否要走 Rpc 调用。如果要走 Rpc 可以用 Dubbo 的泛化调用。