微服务最佳实践,零改造实现 Spring Cloud Apache Dubbo 互通

作者:孙彩荣

很遗憾,这不是一篇关于中间件理论或原理讲解的文章,没有高深晦涩的工作原理分析,文后也没有令人惊叹的工程数字统计。本文以实际项目和代码为示例,一步一步演示如何以最低成本实现 Apache Dubbo 体系与 Spring Cloud 体系的互通,进而实现不同微服务体系的混合部署、迁移等,帮助您解决实际架构及业务问题。

背景与目标

如果你在微服务开发过程中正面临以下一些业务场景需要解决,那么这篇文章可以帮到您:

  • 您已经有一套基于 Dubbo 构建的微服务应用,这时你需要将部分服务通过 REST HTTP 的形式(非接口、方法模式)发布出去,供一些标准的 HTTP 端调用(如 Spring Cloud 客户端),整个过程最好是不用改代码,直接为写好的 Dubbo 服务加一些配置、注解就能实现。
  • 您已经有一套基于 Spring Cloud 构建的微服务体系,而后又构建了一套 Dubbo 体系的微服务,你想两套体系共存,因此现在两边都需要调用到对方发布的服务。也就是 Dubbo 应用作为消费方要调用到 Spring Cloud 发布的 HTTP 接口,Dubbo 应用作为提供方还能发布 HTTP 接口给 Spring Cloud 调用。
  • 出于一些历史原因,你正规划从一个微服务体系迁移到另外一个微服务体系,前提条件是要保证中间过程的平滑迁移。

在这里插入图片描述

对于以上几个场景,我们都可以借助 Dubbo3 内置的 REST 编程范式支持实现,这让 Dubbo 既可以作为消费方调用 HTTP 接口的服务,又可以作为提供方对外发布 REST 风格的 HTTP 服务,同时整个编码过程支持业界常用的 REST 编程范式(如 JAX-RS、Spring MVC 等),因此可以做到基本不改动任何代码的情况下实现 Dubbo 与 Spring Cloud 体系的互相调用。

  • 关于这一部分更多的设计与理论阐述请参见这里的博客文章 [ 1]
  • 关于 Dubbo REST 的更多配置方式请参见 rest 使用参考手册 [ 2]

示例一:Dubbo 调用 Spring Cloud

在已经有一套 Spring Cloud 微服务体系的情况下,演示如何使用 Dubbo 调用 Spring Cloud 服务(包含自动的地址发现与协议传输)。在注册中心方面,本示例使用 Nacos 作为注册中心,对于 Zookeeper、Consul 等两种体系都支持的注册中心同样适用。

在这里插入图片描述

设想你已经有一套 Spring Cloud 的微服务体系,现在我们将引入 Dubbo 框架,让 Dubbo 应用能够正常的调用到 Spring Cloud 发布的服务。本示例完整源码请参见 samples/dubbo-call-sc [ 3]

启动 Spring Cloud Server

示例中 Spring Cloud 应用的结构如下:

在这里插入图片描述

应用配置文件如下:

server:port: 8099
spring:application:name: spring-cloud-provider-for-dubbocloud:nacos:serverAddr: 127.0.0.1:8848 #注册中心

以下是一个非常简单的 Controller 定义,发布了一个 /users/list/的 http 端点。

@RestController
@RequestMapping("/users")
public class UserController {@GetMapping("/list")public List<User> getUser() {return Collections.singletonList(new User(1L, "spring cloud server"));}
}

启动 SpringCloudApplication,通过 cURL 或浏览器访问 http://localhost:8099/users/list 可以测试应用启动成功。

使用 Dubbo Client 调用服务

Dubbo client 也是一个标准的 Dubbo 应用,项目基本结构如下:

在这里插入图片描述

其中,一个比较关键的是如下接口定义(正常情况下,以下接口可以直接从原有的 Spring Cloud client 应用中原样拷贝过来即可,无需做任何修改)。

如果之前没有基于 OpenFeign 的 Spring Cloud 消费端应用,那么就需要自行定义一个接口,此时不一定要使用 OpenFeign 注解,使用 Spring MVC 标准注解即可。

通过 DubboReference 注解将 UserServiceFeign 接口注册为 Dubbo 服务。

@DubboReference
private UserServiceFeign userService;

接下来,我们就可以用 Dubbo 标准的方式对服务发起调用了。

List<User> users = userService.users();

通过 DubboConsumerApplication 启动 Dubbo 应用,验证可以成功调用到 Spring Cloud 服务。

示例二:Spring Cloud 调用 Dubbo

在接下来的示例中,我们将展示如何将 Dubbo server 发布的服务开放给 Spring Cloud client 调用。

在这里插入图片描述

示例的相关源码在 samples/sc-call-dubbo [ 4]

启动 Dubbo Server

Dubbo server 应用的代码结构非常简单,是一个典型的 Dubbo 应用。

在这里插入图片描述

相比于普通的 Dubbo 服务定义,我们要在接口上加上如下标准 Spring MVC 注解:

@RestController
@RequestMapping("/users")
public interface UserService {@GetMapping(value = "/list")List<User> getUsers();
}

除了以上注解之外,其他服务发布等流程都一致,使用 DubboService 注解发布服务即可:

@DubboService
public class UserServiceImpl implements UserService {@Overridepublic List<User> getUsers() {return Collections.singletonList(new User(1L, "Dubbo provider!"));}
}

在服务配置上,特别注意我们需要将服务的协议配置为 rest protocol: rest,地址发现模式使用 register-mode: instance:

dubbo:registry:address: nacos://127.0.0.1:8848register-mode: instanceprotocol:name: restport: 8090

启动 Dubbo 应用,此时访问以下地址可以验证服务运行正常:http://localhost:8090/users/list

使用 Spring Cloud 调用 Dubbo

使用 OpenFeign 开发一个标准的 Spring Cloud 应用,即可调用以上发布的 Dubbo 服务,项目代码结构如下:

在这里插入图片描述

其中,我们定义了一个 OpenFeign 接口,用于调用上面发布的 Dubbo rest 服务。

@FeignClient(name = "dubbo-provider-for-spring-cloud")
public interface UserServiceFeign {@RequestMapping(value = "/users/list", method = RequestMethod.GET)List<User> getUsers();
}

定义以下 controller 作为 OpenFeign 和 RestTemplate 测试入口:

public class UserController {private final RestTemplate restTemplate;private final UserServiceFeign userServiceFeign;public UserController(RestTemplate restTemplate,UserServiceFeign userServiceFeign) {this.restTemplate = restTemplate;this.userServiceFeign = userServiceFeign;}@RequestMapping("/rest/test1")public String doRestAliveUsingEurekaAndRibbon() {String url = "http://dubbo-provider-for-spring-cloud/users/list";System.out.println("url: " + url);return restTemplate.getForObject(url, String.class);}@RequestMapping("/rest/test2")public List<User> doRestAliveUsingFeign() {return userServiceFeign.getUsers();}
}

根据以上 Controller 定义,我们可以分别访问以下地址进行验证:

  • OpenFeign 方式: http://localhost:8099/dubbo/rest/test1
  • RestTemplage 方式: http://localhost:8099/dubbo/rest/test2

为 Dubbo Server 发布更多的服务

我们可以利用 Dubbo 的多协议发布机制,为一些服务配置多协议发布。接下来,我们就为上面提到的 Dubbo server 服务增加 dubbo tcp 协议发布,从而达到以下部署效果,让这个 Dubbo 应用同时服务 Dubbo 微服务体系和 Spring Cloud 微服务体系。

在这里插入图片描述

为了实现这个效果,我们只需要在配置中增加多协议配置即可:

dubbo:protocols:- id: restname: restport: 8090- id: dubboname: dubboport: 20880

同时,服务注解中也配置为多协议发布:

@DubboService(protocol="rest,dubbo")
public class UserServiceImpl implements UserService {}

这样,我们就成功的将 UserService 服务以 dubbo 和 rest 两种协议发布了出去(多端口多协议的方式),dubbo 协议为 Dubbo 体系服务,rest 协议为 Spring Cloud 体系服务。

注意: Dubbo 为多协议发布提供了单端口、多端口两种方式,这样的灵活性对于不同部署环境下的服务会有比较大的帮助。在确定您需要的多协议发布方式前,请提仔细阅读以下多协议配置 [ 5] 文档。

总结

基于 Dubbo 的 rest 编程范式、多协议发布等特性,可以帮助你轻松的实现 Dubbo 服务的 http 协议发布,让后端服务基于 RPC 高效通信的同时,能够更容易的与 http 服务体系打通,本示例通过 Dubbo 与 Spring Cloud 两套体系的共存、互通示例非常清晰的演示了编码过程。

此部分内容的正式版本将在 Dubbo 3.3.0 版本正式发布,同时还包含 Triple 协议的重磅升级,敬请期待!

相关链接:

[1] 博客文章

https://cn.dubbo.apache.org/zh-cn/blog/2023/01/05/dubbo-%e8%bf%9e%e6%8e%a5%e5%bc%82%e6%9e%84%e5%be%ae%e6%9c%8d%e5%8a%a1%e4%bd%93%e7%b3%bb-%e5%a4%9a%e5%8d%8f%e8%ae%ae%e5%a4%9a%e6%b3%a8%e5%86%8c%e4%b8%ad%e5%bf%83/

[2] rest 使用参考手册

https://cn.dubbo.apache.org/zh-cn/overview/reference/proposals/protocol-http/

[3] samples/dubbo-call-sc

https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-springcloud/dubbo-call-sc

[4] samples/sc-call-dubbo

https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-springcloud/sc-call-dubbo

[5] 多协议配置

https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-protocols/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/94181.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Servlet实现的管理系统(包含服务器源码+数据库)

资料下载链接 介绍 基于Servlet框架的管理系统 简洁版 &#xff1b; 实现 登录 、 注册 、 增 、 删 、 改 、 查 &#xff1b; 可继续完善增加前端、校验、其他功能等&#xff1b; 可作为 Servlet项目 开发练习基础模型&#xff1b; 课程设计 、 毕业设计 开发基础&…

Git 删除 GitHub仓库的文件

新建文件夹 git bash here 在新建的文件夹里右键git bash here打开终端&#xff0c;并执行git init初始化仓库 git clone <你的地址> 找到github上要删除的仓库地址&#xff0c;并复制&#xff0c;在终端里输入git clone <你的地址> 要删除文件的库里右键git b…

Fine tune简介

目录 Intro Related work Example .1 重新训练 .2 使用新的数据集进行fine tune .3 修改net结构 References 移学习不是一种算法而是一种机器学习思想,应用到深度学习就是微调(Fine-tune)。通过修改预训练网络模型结构(如修改样本类别输出个数),选择性载入预训练网络…

【云原生,k8s】基于Helm管理Kubernetes应用

第四阶段 时 间&#xff1a;2023年8月18日 参加人&#xff1a;全班人员 内 容&#xff1a; 基于Helm管理Kubernetes应用 目录 一、Kubernetes部署方式 &#xff08;一&#xff09;minikube &#xff08;二&#xff09;二进制包 &#xff08;三&#xff09;Kubeadm …

【JUC】线程池ThreadPoolTaskExecutor与面试题解读

1、ThreadPoolTaskExecutor 创建线程池 从它的创建和使用说起&#xff0c;创建和使用的代码如下&#xff1a; 创建&#xff1a; ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize…

爬虫逆向实战(十五)--阿某某营登录

一、数据接口分析 主页地址&#xff1a;阿某某营 1、抓包 通过抓包可以发现登录接口是Users/Login 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现有一个s加密参数 请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无cookie是…

【果树农药喷洒机器人】Part7:静态PWM变量喷药实验

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测

分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测 目录 分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.Matlab实现WOA-CNN-BiGRU-Attention多特征分类预测&#xff0c;多特征输入模型&…

C++——移动构造和完美转发

1.什么是右值 右值引用是C11的概念&#xff0c;与之对应的是左值引用。 当一个对象被用作右值的时候&#xff0c;用的是对象的值(内容)&#xff1b;当对象被用作左值的时候&#xff0c;用的是对象的身份(在内存当中的位置)。 以上的概念是摘录自《C primer》。 但是这样的概…

hdu8-Congruences(中国剩余定理)

Problem - 7363 (hdu.edu.cn) 参考&#xff1a;2023杭电暑假多校8 题解 3 5 7 10 | JorbanS_JorbanS的博客-CSDN博客 题解&#xff1a;&#xff08;中国剩余定理 增量法&#xff09; 注意验证和特判&#xff0c;此题中 pi 两两互质&#xff0c;可用CRT和增量法&#xff0c;当…

Linux 进程替换

一、进程替换 把一个进程替换为另外一个进程。对于进程&#xff0c;如果单纯只看复制或者单纯只看替换&#xff0c;没有太大的意义。将复制和替换结合在一起&#xff08;forkexec&#xff09;&#xff0c;就是系统去产生一个全新进程的一种方式。 将复制和替换结合在一起&…

MySQL—缓存

目录标题 为什么要有Buffer Poolbuffer pool有多大buffer pool缓存什么 如何管理Buffer Pool如何管理空闲页如何管理脏页如何提高缓存命中率预读失效buffer pool污染 脏页什么时候会被刷入到磁盘 为什么要有Buffer Pool 虽然说MySQL的数据是存储在磁盘中&#xff0c;但是也不能…

爬虫IP时效问题:优化爬虫IP使用效果实用技巧

目录 1. 使用稳定的代理IP服务提供商&#xff1a; 2. 定期检测代理IP的可用性&#xff1a; 3. 配置合理的代理IP切换策略&#xff1a; 4. 使用代理IP池&#xff1a; 5. 考虑代理IP的地理位置和速度&#xff1a; 6. 设置合理的请求间隔和并发量&#xff1a; 总结 在爬虫过…

【JAVA】数组练习

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 数组练习 1. 数组转字符串2. 数组拷贝3.…

Layui列表复选框根据条件禁用

// 禁用客服回访id有值的复选框res.data.forEach(function (item, i) {if (item.feedbackEmpId) {let index res.data[i][LAY_TABLE_INDEX];$(".layui-table tr[data-index"index"] input[typecheckbox]").prop(disabled,true);$(".layui-table tr[d…

c++--SLT六大组件之间的关系

1.SLT六大组件&#xff1a; 容器&#xff0c;迭代器&#xff0c;算法&#xff0c;仿函数&#xff0c;适配器&#xff0c;空间配置器 2.六大组件之间的关系 容器&#xff1a;容器是STL最基础的组件&#xff0c;没有容器&#xff0c;就没有数据&#xff0c;容器的作用就是用来存…

【ArcGIS Pro二次开发】(60):按图层导出布局

在使用布局导图时&#xff0c;会遇到如下问题&#xff1a; 为了切换图层和导图方便&#xff0c;一般情况下&#xff0c;会把相关图层做成图层组。 在导图的时候&#xff0c;如果想要按照图层组进行分开导图&#xff0c;如上图&#xff0c;想导出【现状图、规划图、管控边界】3…

【数据结构】 ArrayList简介与实战

文章目录 什么是ArrayListArrayList相关说明 ArrayList使用ArrayList的构造无参构造指定顺序表初始容量利用其他 Collection 构建 ArrayListArrayList常见操作获取list有效元素个数获取和设置index位置上的元素在list的index位置插入指定元素删除指定元素删除list中index位置上…

电商增强现实3D模型优化需要关注的4个方面

到目前为止&#xff0c;AR技术已经发展到足以在更广泛的范围内实施。 在电子商务中&#xff0c;这项技术有望提供更令人兴奋的购物体验。 为了实现这一目标&#xff0c;在这篇博客中&#xff0c;我将介绍如何针对电子商务中的 AR 优化 3D 模型。 推荐&#xff1a;用 NSDT编辑器…

企业计算机服务器中了360后缀勒索病毒怎么办,勒索病毒解密数据恢复

随着计算机技术的不断发展&#xff0c;企业的办公系统得到了很大提升&#xff0c;但是随之而来的网络安全威胁也不断增加&#xff0c;勒索病毒的攻击事件时有发生。近期&#xff0c;我们收到某地连锁超市的求助&#xff0c;企业的计算机服务器遭到了360后缀勒索病毒攻击&#x…