dubbo服务管控

news2024/12/23 9:18:45

我们已经介绍了Dubbo在服务治理方面提供的特性,今天我们一起来看看Dubbo在其它方面提供的特性。同服务治理篇一样,本文的目的在于学会使用Dubbo在服务管控方面提供的特性,依旧不涉及任何实现原理。

工程结构

嗯~~

是这样的,因为电脑过于拉胯,而且IDEA着实有些吃内存了,所有我将测试工程按照子项目合并到一起了,目前我使用的工程结构是这样的:

子模块名由两部分组成:配置方式+功能,如:XMLProvider,表示以XML配置方式为主的服务提供方。

Tips:IDEA快要追上“内存雄狮”CLionl了。

本地存根(Stub)

使用Dubbo时,服务使用方只集成了接口,所有的实现全都在服务提供方,但部分场景中,我们希望服务使用方完成一些逻辑的处理,以此来减少RPC交互带来的性能消耗,例如:将参数校验放在服务使用方去做,减少一次与服务调用方的网络交互。

这种场景中,我们可以使用Dubbo提供的本地存根特性。我们有如下的服务提供方的工程结构:

xml-provider-api模块中定义了对外提供服务的接口XMLProviderService,代码如下:

public interface XMLProviderService {
	String say(String message);
}

以及接口存根XMLProviderServiceStub,代码如下:

public class XMLProviderServiceStub implements XMLProviderService {

	private final XMLProviderService xmlProviderService;

	public XMLProviderServiceStub(XMLProviderService xmlProviderService) {
		this.xmlProviderService = xmlProviderService;
	}

	@Override
	public String say(String message) {
		if (StringUtils.isBlank(message)) {
			return "message不能为空!";
		}

		try {
			return this.xmlProviderService.say(message);
		} catch (Exception e) {
			return "远程调用失败:" + e.getMessage();
		}
	}
}

接着我们在服务使用方的工程中配置接口存根:

<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" stub="com.wyz.api.stub.XMLProviderServiceStub"/>

Tips:使用本地存根,要求存根的实现类必须有传入Proxy实例(服务使用方提生成的Proxy实例)的构造函数。

本地伪装(Mock)

本地伪装即我们在《Dubbo的高级特性:服务治理篇》中提到的服务降级,我们今天再稍微做一个补充。本地伪装是本地存根的一个子集,本地存根可以处理RPC调用环节中各种各样的错误和异常,而本地伪装则专注于处理RpcException(如网络失败,响应超时等)这种需要容错处理的异常

我们为XMLProviderService添加一个本地伪装服务XMLProviderServiceMock,工程结构如下:

XMLProviderServiceMock的代码如下:

public class XMLProviderServiceMock implements XMLProviderService {

	@Override
	public String say(String message) {
		return "服务出错了!";
	}
}

配置文件可以按如下方式配置:

<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" mock="true"/>

这种配置中,要求Mock的实现必须按照“接口名+Mock后缀”的方式进行命名;如果不想使用这种命名方式,可以使用全限名:

<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" mock="com.wyz.api.mock.XMLProviderServiceMock"/>

Tips:再“重复”一遍Mock的原因是,上一篇中出了一点错误,本应在<dubbo:reference>标签中做的配置,我写到了<dubbo:service>标签中,产生错误的原因还是没有动手在项目中写一写,哎,真应了那句“纸上得来终觉浅,绝知此事要躬行”。

参数回调

Dubbo支持参数回调功能,使服务提供方可以“反向”调用服务使用方,该功能是基于长链接生成的反向代理实现的,效果类似于异步调用。我们举个支付的例子:

XMLProvider工程的xml-provider-api模块中添加PaymentService接口,同时添加PaymentNotifyService用于通知PaymentService的结果:

public interface PaymentService {
	void payment(String cardNo, PaymentNotifyService paymentNotifyService);
}

public interface PaymentNotifyService {
	void paymentNotify(String message);
}

XMLProvider工程的xml-provider-service模块中实现PaymentService接口:

public class PaymentServiceImpl implements PaymentService {
	@Override
	public void payment(String cardNo, PaymentNotifyService paymentNotifyService) {
		System.out.println("向卡号[" + cardNo + "]付钱!");
		// 业务逻辑
		paymentNotifyService.paymentNotify("付款成功");
	}
}

执行PaymentService#payment方法,并调用PaymentNotifyService#paymentNotify方法通知服务调用方执行结果。

XMLConsumer工程中实现PaymentNotifyService接口:

public class PaymentNotifyServiceImpl implements PaymentNotifyService {
	@Override
	public void paymentNotify(String message) {
		System.out.println("支付结果:" + message);
	}
}

来看一下此时的工程结构:

接下来是XML的配置,参数回调中,我们需要关注的是服务提供方XMLProvider工程的xml-provider-service模块的配置:

<bean id="paymentServiceImpl" class="com.wyz.service.impl.PaymentServiceImpl"/>
<dubbo:service interface="com.wyz.api.PaymentService" ref="paymentServiceImpl" callbacks="10">
  <dubbo:method name="payment">
    <dubbo:argument index="1" callback="true"/>
  </dubbo:method>
</dubbo:service>

配置通过第4行的<dubbo:argument index="1" callback="true"/>来确定PaymentService#payment方法中第2个(index从0开始)参数是回调参数;callbacks限制了同一个长链接下回调的次数,而不是总共回调的次数。

Tips:在实际的支付业务场景中,更倾向于异步处理,比如服务提供方在接收到支付请求是,启动新线程处理支付业务并调用通知接口,主线程返回成功接收支付请求。

异步调用

异步调用允许服务提供方立即返回响应,同时后台继续执行请求处理,当服务使用方请求响应结果时,服务提供方将结果返回。

DUbbo支持两种异步调用方式:

  • 使用CompletableFuture接口
  • 使用RpcContext

DUbbo 2.7之后,DUbbo以CompletableFuture接口为异步编程的基础。

使用CompletableFuture实现异步调用

我们先来看如何使用CompletableFuture实现异步调用,声明CompletableFutureAsyncService接口:

public interface CompletableFutureAsyncService {
	CompletableFuture<String> async(String message);
}

接着是接口实现:

public class CompletableFutureAsyncServiceImpl implements CompletableFutureAsyncService {
	@Override
	public CompletableFuture<String> async(String message) {
		return CompletableFuture.supplyAsync(() -> {
			System.out.println(Thread.currentThread().getName() + " say : " + message);

			try {
				TimeUnit.SECONDS.sleep(10);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			return "异步调用成功!";
		});
	}
}

XML配置与普通的DubboRPC接口配置相同,xml-provider-service模块的配置:

<bean id="completableFutureAsyncServiceImpl" class="com.wyz.service.impl.CompletableFutureAsyncServiceImpl" />
<dubbo:service interface="com.wyz.api.CompletableFutureAsyncService" ref="completableFutureAsyncServiceImpl" />

XMLConsumer模块的配置:

<dubbo:reference id="completableFutureAsyncService" interface="com.wyz.api.CompletableFutureAsyncService"/>

使用方式也非常简单:

CompletableFuture<String> completableFuture = completableFutureAsyncService.async("Hello");
System.out.println(completableFuture.get());

Tips

  • Dubbo中使用CompletableFuture与单独使用CompletableFuture并无什么差异~~
  • CompletableFutureAsyncServiceImpl的实现中打印接口名称的目的是为了清晰的展示出异步调用的效果;
  • CompletableFuture#supplyAsync(Supplier<U> supplier)默认使用ForkJoinPool#commonPool()
  • 重载方法CompletableFuture#supplyAsync(Supplier<U> supplier, Executor executor)允许使用自定义线程池。

使用AsyncContext实现异步调用

除了使用CompletableFuture外,还可以通过Dubbo定义的AsyncContext实现异步调用。先来编写接口和接口实现:

public interface RpcContextAsyncService {
	String async(String message);
}

public class RpcContextAsyncServiceImpl implements RpcContextAsyncService {

	@Override
	public String async(String message) {
		final AsyncContext asyncContext = RpcContext.startAsync();
		new Thread(() -> {
			asyncContext.signalContextSwitch();
			asyncContext.write(Thread.currentThread().getName() + " say : " + message);
		}).start();
		// 异步调用中,这个返回值完全没有意义
		return null;
	}
}

服务提供方的配置与其它Dubbo接口的配置并无不同:

<bean id="rpcContextAsyncServiceImpl" class="com.wyz.service.impl.RpcContextAsyncServiceImpl"/>
<dubbo:service interface="com.wyz.api.RpcContextAsyncService" ref="rpcContextAsyncServiceImpl"/>

接着是服务使用方的配置,需要添加async参数:

<dubbo:reference id="rpcContextAsyncService" interface="com.wyz.api.RpcContextAsyncService" async="true"/>

最后是在服务使用方中调用RPC接口:

rpcContextAsyncService.async("Thanks");

Future<String> future = RpcContext.getServiceContext().getFuture();
System.out.println(future.get());

泛化调用

Dubbo的泛化调用提供了一种不依赖服务提供方API(SDK)的而调用服务的实现方式。主要场景在于网关平台的实现,通常网关的实现不应该依赖于其他服务的API(SDK)。

Dubbo官方提供了3种泛化调用的方式:

  • 通过API使用泛化调用
  • 通过Spring使用泛化调用(XML形式)
  • Protobuf对象泛化调用

这里我们介绍以XML的形式配置泛化调用的方式。

准备工作

首先我们再准备一个服务提供的工程GenericProvider,工程结构如下:

工程中定义了接口即实现类GenericProviderService和GenericProviderServiceImpl,代码如下:

public interface GenericProviderService {
	String say(String message);
}

public class GenericProviderServiceImpl implements GenericProviderService {
	@Override
	public String say(String message) {
		return "GenericProvider say:" + message;
	}
}

generic-dubbo-provider.xml中只需要正常配置GenericProvider提供的服务即可:

'<bean id="genericProviderServiceImpl" class="com.wyz.service.impl.GenericProviderServiceImpl"/>
<dubbo:service interface="com.wyz.service.api.GenericProviderService" ref="genericProviderServiceImpl" generic="true"/>

application.yml文件的配置我们就不多赘述了。

服务使用方的配置

回到XMLConsumer工程中,先配置Dubbo服务引用,xml-dubbo-consumer.xml中添加如下内容:

<dubbo:reference id="genericProviderService" generic="true" interface="com.wyz.service.api.GenericProviderService"/>

参数generic声明这是一个泛化调用的服务。此时IDEA会将interface="com.wyz.service.api.GenericProviderService"标红,提示“Cannot resolve class 'GenericProviderService'”,这个我们不需要关注,因为com.wyz.service.api包下确实不存在GenericProviderService接口。

接着我们来使用GenericProviderService接口:

ApplicationContext context = SpringContextUtils.getApplicationContext();
// genericProviderService是XML中定义的服务id
GenericService genericService = (GenericService) context.getBean("genericProviderService");

// $invoke的3个参数分别为:方法名,参数类型,参数
Object result = genericService.$invoke("say", new String[]{"java.lang.String"}, new Object[]{"wyz"});
System.out.println(result);

这样,我们就可以通过ApplicationContext获取到GenericProviderService接口提供的服务了。

Tips:SpringContextUtils用于获取ApplicationContext,代码如下:

@Component
public class SpringContextUtils implements ApplicationContextAware {
	private static ApplicationContext applicationContext = null;

	public static ApplicationContext getApplicationContext() {
		return SpringContextUtils.applicationContext;
	}

	@Override
	public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
		SpringContextUtils.applicationContext = applicationContext;
	}
}

结语

好了,到目前为止,我们已经一起认识并学习了Dubbo中常用特性的配置与使用,当然了,经历了多年的发展,Dubbo的提供的特性远不止于此,如果想要了解更多内容,可以查看阿里巴巴提供的文档《Apache Dubbo微服务框架从入门到精通》。

下一篇,我们从服务注册部分正式开启对Dubbo实现原理的探索。


如果本文对你有帮助的话,还请多多点赞支持。如果文章中出现任何错误,还请批评指正。最后欢迎大家关注分享硬核Java技术的金融摸鱼侠王有志,我们下次再见!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python webdriver 测试框架数据驱动json文件驱动的方式

简介&#xff1a; 数据驱动excel驱动方式,就是数据配置在excel里面&#xff0c;主程序调用的时候每次用从excel里取出的数据作为参数&#xff0c;进行操作&#xff0c; 需要掌握的地方是对excel的操作&#xff0c;要灵活的找到目标数据 测试数据.xlsx: 路径-D:\test\0627 E…

设计模式之代理模式与外观模式

目录 代理模式 简介 优缺点 角色职责 实现 运用场景 外观模式 简介 角色职责 优缺点 实现 使用场景 代理模式 简介 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时&#xff0c;访问对象不适合或者不能直接引用目标对象&#xff0c;代理对象作为…

京东搜索EE链路演进 | 京东云技术团队

导读 搜索系统中容易存在头部效应&#xff0c;中长尾的优质商品较难获得充分的展示机会&#xff0c;如何破除系统的马太效应&#xff0c;提升展示结果的丰富性与多样性&#xff0c;助力中长尾商品成长是电商平台搜索系统的一个重要课题。其中&#xff0c;搜索EE系统在保持排序…

北美电池测试标准解读:UL 1642、UL 2054、UL 2056、UL 2089 测试报告

在日常生活中人们与各类电子产品的交流和互动越来越多&#xff0c;由于电池与人们的接触日益密切&#xff0c;电池的安全性显得格外重要&#xff0c;因此越来越多商家注重保证电池的安全性&#xff0c;避免因电池安全事故带来的人身伤害和品牌名誉损失。特别是亚马逊今年开年来…

无涯教程-JavaScript - DMIN函数

描述 DMIN函数返回列表或数据库中符合您指定条件的列中的最小数字。 语法 DMIN (database, field, criteria)争论 Argument描述Required/Optionaldatabase 组成列表或数据库的单元格范围。 数据库是相关数据的列表,其中相关信息的行是记录,数据的列是字段。列表的第一行包含…

动辄百万的工业数据处理软件,现在60秒就能用上

刚刚过去的周五&#xff0c;TDengine团队正式发布了新版3.1.1.0, 并上线了新的官网。虽没有发布会&#xff0c;但对涛思数据而言&#xff0c;这是一个“蓄谋已久”的动作。因为新版TDengine里包含了一个核心模块taosX&#xff0c;它具备强大的数据抓取、清洗、转换、加载(ETL)功…

金九银十,软件测试最新面试题整理(超详细~)

1、创建坐席组的功能模块&#xff0c;如何进行测试用例设计&#xff1f; 解答&#xff1a; 功能测试&#xff0c;使用等价类划分法去分析创建坐席的每个输入项的有效及无效类&#xff0c;同步考虑边界值去设计对应的测试用例&#xff1a; 先进行冒烟测试&#xff0c;正常创建…

微信小程序新版canvas2d海报绘制(教你轻松搞定)

效果 说明&#xff1a; canvas官方很早已经发声不再维护了&#xff0c;所以很多方法都已经不再适用。目前官方推荐适用canvas2d来绘制生成海报。 canvas2d来绘制海报&#xff1a; canvas2d的优点&#xff1a; 例如&#xff1a; 不需要先预下载网络图片再绘制&#xff0c;前…

【Hello Algorithm】二叉树相关算法

本篇博客介绍&#xff1a;介绍二叉树的相关算法 二叉树相关算法 二叉树结构遍历二叉树递归序二叉树的交集非递归方式实现二叉树遍历二叉树的层序遍历 二叉树难题二叉树的序列化和反序列化lc431求二叉树最宽的层二叉树的后继节点谷歌面试题 二叉树结构 如果对于二叉树的结构还有…

C#FreeSql分库分表

using FreeSql; using FreeSql.DataAnnotations;namespace FreeSqlMaster {internal class Program{static IFreeSql freeSql null;static void Main(string[] args){// 读写分离// FreeSql 实现了第3种方案&#xff0c;支持一个【主库】多个【从库】&#xff0c;【从库】的查…

MPU6050姿态手势控制:二自由度云台

使用芯片&#xff1a;STM32 F103 C8T6 开源一款 MPU6050姿态手势控制二自由度云台 的设计程序与硬件清单&#xff0c;文章会贴出基本原理所需学习的文章连接&#xff0c;测试效果&#xff0c;元件清单&#xff0c;工程下载。 之前有做过二自由度机械臂的开发&#xff0c;但材…

阿里巴巴新一代SpringCloud学习指南重磅发布,揭示中国特色微服务组件的奥秘

SpringCloud Alibaba 的优势 阿里使用过的组件经历了考验&#xff0c;性能强悍&#xff0c;设计合理&#xff0c;现在开源出来给大家用。成套产品搭配完善的可视化界面给开发运维带来了极大的便利。搭建简单&#xff0c;学习曲线低。 作为国内微服务领域的领军企业&#xff0…

“钉钉官网首页的炫酷动效” 被我用css新特性轻松破解啦~

&#x1f33b; 前言 其实写本文的初衷只是想分享一个css新特性【scroll-timeline】&#x1f602;,但是我想要体现出它的强大效果&#xff0c;此时正好想到了之前看到过钉钉的首页动画&#xff0c;就是滚动页面然后进行一系列动画的&#xff0c;所以我决定实现一下这个效果。&am…

ChatGPT AIGC 完成动态堆积面积图实例

先使用ChatGPT AIGC描述一下堆积面积图的功能与作用。 接下来一起看一下ChatGPT做出的动态可视化效果图: 这样的动态图案例代码使用ChatGPT AIGC完成。 将完整代码复制如下: <!DOCTYPE html> <html> <head><meta charset="utf-8"><tit…

为反应系统实现MQTT客户端

MQTT-Reactive的目的是提供一种用C编写的可移植且无阻塞的MQTT客户端&#xff0c;以便在反应式嵌入式系统中使用。首先&#xff0c;本文说明什么是反应系统。然后&#xff0c;它描述了如何为这种系统设计合适的软件结构。最后&#xff0c;本文展示了如何通过使用状态机和事件驱…

【校招VIP】测试技术考点之单元测试集成测试

考点介绍&#xff1a; 单元测试,集成测试的区别是&#xff1a;方式不同、粒度不同、内容不同。单元测试用用于验证编码单元的正确性。集成测试用于验证详细设计。体现了测试由小到大、又内至外、循序渐进的测试过程和分而治之的思想。 测试技术考点之单元测试&集成测试-相…

WIN11有网络但浏览器打不开

打开设置-》网络和INTERNET-》代理&#xff0c;将自动检测设置打开&#xff0c;将手动设置代理中的使用代理服务器关闭。就可以打开浏览器了。 不知道为什么会出现这样的问题

【数据分享】2009-2021年我国省份级别的轨道交通相关指标(30多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国省份级别的市政设施水平相关指标、2006-2021年我国省份级别的各类建设用地面积数…

vue3 搭配ElementPlus做基础表单校验 自定义表单校验

<script setup> import { ref, reactive } from vue// 表单元素 const dom ref(null) // 校验规则 const rules {name: [{ required: true, message: 请输入活动名称, trigger: blur }],//校验手机号格式phone: [{ required: true, message: "请输入电话", t…

问道管理:证券市场也有中介机构吗?他们具体干什么?

证券市场是一个很大的发行流通生意市场&#xff0c;在这个市场上&#xff0c;有许许多多不同的生意主体。而有生意就会有中介&#xff0c;证券市场上也有中介组织吗&#xff1f;如果有&#xff0c;他们具体又是干什么的&#xff1f;关于这些&#xff0c;问道管理为我们预备了以…