java-design-patterns 中的 Ambassador 模式:为遗留远程服务构建客户端侧代理

📅 发布时间:2026/10/2 20:54:22
java-design-patterns 中的 Ambassador 模式:为遗留远程服务构建客户端侧代理
示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载Ambassador大使模式的核心思想是在客户端旁边部署一个辅助服务实例由它代为执行远程共享资源的通用连接功能。本文以 java-design-patterns 仓库中的ambassador模块为主线通过完整的 Java 源码示例讲解该模式如何为难以修改的遗留远程服务注入限流、延迟检测、日志与重试能力读完即可理解其角色划分、关键实现与适用场景并可直接对照仓库源码动手运行验证。模式目标PropósitoAmbassador 模式为客户端提供一个辅助服务实例并将访问共享远程资源时常见的横切功能委托给该实例处理。翻译自微软官方架构文档的定义指出Ambassador 服务可以看作是与客户端共存于同一进程外的代理out-of-process proxy它适合用来承接客户端侧的通用连接任务——如监控、日志、路由、安全例如 TLS与弹性resilience处理并且这些能力的实现与语言无关。该模式经常与遗留应用或其他难以修改的应用搭配使用用以扩展其网络能力同时也能让专门的团队独立落地这些特性。在 java-design-patterns 的 ambassador 模块 中模块的入口类 App.java 的注释对这一意图做了同样的概括大使服务为另一个远程服务提供接口同时额外承载监控、日志、路由、安全等被“卸载”下来的通用连接任务这对代码库难以改造的遗留应用尤其有价值。动机一个真实的遗留服务场景文档给出了一个非常贴近实际的例子一个远程服务拥有大量客户端访问其提供的某项功能。该服务是遗留应用已经无法升级。大量用户请求正在引发连接问题。需要在客户端侧实现新的请求频率限制规则同时加入延迟latency检测与日志记录。这正是 Ambassador 模式的典型发力点远程服务本身不可修改所有增强能力只能在客户端侧完成。如果把这些逻辑直接塞进每个客户端会造成大量重复代码并侵入业务逻辑而 Ambassador 模式把这些共性能力收敛到一个专门的辅助对象中让客户端代码保持干净。核心角色与协作关系从仓库源码可以归纳出该模式在本项目中的四个参与角色对应包com.iluwatar.ambassador下的类角色类/接口职责共享接口RemoteServiceInterface.java声明long doRemoteFunction(int value)由远程服务与大使服务共同实现保证客户端面向接口编程远程服务RemoteService.java以单例Singleton形式模拟遗留远程应用执行真正的业务计算并模拟随机耗时与偶发失败大使服务ServiceAmbassador.java实现同一接口在调用远程服务前附加延迟检测、日志与带退避的重试客户端Client.java只与本地大使服务交互不直接接触远程服务类图见 ambassador/etc/ambassador.urm.pngPlantUML 源文件位于 ambassador/etc/ambassador.urm.puml可以清晰看到RemoteService与ServiceAmbassador都实现RemoteServiceInterface而Client仅持有ServiceAmbassador引用。代码示例完整实现1. 共享接口远程服务与大使服务都实现同一个接口这是模式的关键——对客户端而言大使服务就是远程服务的“本地替身”interface RemoteServiceInterface { long doRemoteFunction(int value) throws Exception; }2. 远程服务遗留应用模拟远程服务以单例形式存在源码中由static synchronized getRemoteService()保证唯一实例每次调用会随机睡眠 0~999ms并根据延迟是否超过阈值THRESHOLD源码中为 200ms决定返回value * 10还是失败值-1Slf4j public class RemoteService implements RemoteServiceInterface { private static RemoteService service null; static synchronized RemoteService getRemoteService() { if (service null) { service new RemoteService(); } return service; } private RemoteService() {} Override public long doRemoteFunction(int value) { long waitTime (long) Math.floor(Math.random() * 1000); try { sleep(waitTime); } catch (InterruptedException e) { LOGGER.error(Thread sleep interrupted, e); } return waitTime 200 ? value * 10 : -1; } }需要说明的是当前仓库源码 RemoteService.java 在示例基础上做了两处演进——随机数生成被抽象为 RandomProvider.java 接口便于测试注入固定值成功/失败的魔法数字-1被提炼为 RemoteServiceStatus.java 枚举常量FAILURE(-1)。此外源码将成功条件统一为waitTime THRESHOLD与文档示例中waitTime 200的写法在语义上互为镜像实际效果一致延迟不超过 200ms 即成功。注释中明确说明这种随机耗时与偶发-1是为了模拟客户端必须应对的连接问题。3. 大使服务核心增强逻辑ServiceAmbassador是模式的灵魂它实现了延迟检测与带退避的重试防止在远程服务出现连接问题时继续施压。两个关键常量是RETRIES 3最多重试次数与DELAY_MS 3000重试前等待 3 秒Slf4j public class ServiceAmbassador implements RemoteServiceInterface { private static final int RETRIES 3; private static final int DELAY_MS 3000; ServiceAmbassador() { } Override public long doRemoteFunction(int value) { return safeCall(value); } private long checkLatency(int value) { var startTime System.currentTimeMillis(); var result RemoteService.getRemoteService().doRemoteFunction(value); var timeTaken System.currentTimeMillis() - startTime; LOGGER.info(Time taken (ms): timeTaken); return result; } private long safeCall(int value) { var retries 0; var result (long) FAILURE; for (int i 0; i RETRIES; i) { if (retries RETRIES) { return FAILURE; } if ((result checkLatency(value)) FAILURE) { LOGGER.info(Failed to reach remote: ( (i 1) )); retries; try { sleep(DELAY_MS); } catch (InterruptedException e) { LOGGER.error(Thread sleep state interrupted, e); } } else { break; } } return result; } }对照源码 ServiceAmbassador.java其类注释将这套机制概括为为 Client 提供访问 RemoteService 的接口并以一种在连接出问题时不会给远程服务增加压力的安全方式附加日志、延迟测试与服务调用。这正是 Ambassador 模式“卸载共性连接任务”价值的具体化checkLatency记录调用耗时毫秒这是客户端侧延迟监控的雏形safeCall失败后最多重试RETRIES次每次间隔DELAY_MS形成最简单的熔断/退避语义避免雪崩式重试压垮遗留服务。4. 客户端客户端只持有一个本地大使服务实例业务代码保持简洁完全不感知重试与延迟检测的细节Slf4j public class Client { private final ServiceAmbassador serviceAmbassador new ServiceAmbassador(); long useService(int value) { var result serviceAmbassador.doRemoteFunction(value); LOGGER.info(Service result: result); return result; } }5. 组装与运行两个客户端同时使用该服务对应源码 App.java 中的main方法public class App { public static void main(String[] args) { var host1 new Client(); var host2 new Client(); host1.useService(12); host2.useService(73); } }运行结果解读文档给出了运行上述示例后的典型输出Time taken (ms): 111 Service result: 120 Time taken (ms): 931 Failed to reach remote: (1) Time taken (ms): 665 Failed to reach remote: (2) Time taken (ms): 538 Failed to reach remote: (3) Service result: -1可以这样解读host1value12首次调用延迟 111ms低于阈值成功返回12012 × 10host2value73连续三次调用延迟931ms、665ms、538ms都超过阈值三次尝试全部失败最终返回-1且每次失败后都间隔了 3 秒重试——注意重试后的失败返回值本身已是 -1说明大使层已按RETRIES上限结束尝试。这套调用与重试的时序关系可以参考模块自带的时序图 ambassador/etc/ambassador-sequence-diagram.png客户端调用大使服务大使检查延迟并调用远程服务失败时进入延迟等待后重试直至成功或耗尽次数。模式的价值与适用场景从源码与文档可以确认Ambassador 模式适用且仅适用于这类情境远程服务是遗留系统无法或极难修改需要在不改动远程服务的前提下把连接性能力在客户端侧补齐。它的直接收益包括为远程服务提供一个本地接口抽象了网络细节在客户端实现日志记录、熔断circuit breaking、重试与安全控制而远程服务无需任何改动。典型用例控制对另一个对象的访问实现日志/记录能力实现熔断机制委托远程服务的调用任务简化网络连接的建立与维护这些用例在仓库中的体现非常直观ServiceAmbassador同时承载了日志LOGGER.info、延迟监控checkLatency、重试/熔断safeCall与RETRIES/DELAY_MS常量三类横切能力客户端则只做纯粹的调用与结果展示。与相关模式的关系Ambassador 模式与Proxy 模式关系最为密切两者都提供目标对象的替身接口。区别在于 Proxy 通常聚焦于访问控制与懒加载而 Ambassador 是“进程外代理”专门承载日志、监控、重试、安全等网络横切能力且常与客户端同机部署。java-design-patterns 仓库也收录了独立的 proxy 模块读者可以对照两者的实现差异来加深理解。在仓库中运行与验证模块源码位于 ambassador/src/main/java/com/iluwatar/ambassador测试代码位于 ambassador/src/test/java/com/iluwatar/ambassador含AppTest、ClientTest、RemoteServiceTest、ServiceAmbassadorTest四组测试其中RemoteServiceTest利用RandomProvider注入固定随机值以验证阈值与失败分支。构建信息见 ambassador/pom.xml作为仓库 Maven 多模块工程的一部分可使用仓库根目录的 Maven Wrappermvnw对ambassador模块执行测试例如./mvnw -pl ambassador test直接运行App的main方法即可观察到上文所述的成功/重试/失败日志。小结Ambassador 模式解决的是一个非常现实的工程问题远程服务动不了但连接体验必须提升。java-design-patterns 的ambassador模块用不到十个类就完整演示了该模式的骨架——共享接口、单例远程服务、带延迟检测与退避重试的大使服务、以及纯净的客户端。掌握它之后你可以把它作为在遗留系统周边搭建限流、监控、重试、TLS 等能力层时的参考范式也可以据此理解 Kubernetes 生态中各类 Ambassador/Sidecar 网关组件背后的设计思想。赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐Cherry Studio 数据库测试指南使用 setupTestDatabase 测试主进程 SQLite 数据层Cherry Studio 数据库测试指南使用 setupTestDatabase 测试主进程 SQLite 数据层 Cherry Studio 的持久化层建示例工程教程java-design-patterns 中的 Ambassador大使模式用本地辅助服务化解远程资源调用难题java design patterns 中的 Ambassador大使模式用本地辅助服务化解远程资源调用难题 Ambassador大使模式的核心思想示例工程教程Ambassador模式pybind11客户端代理Ambassador模式pybind11客户端代理 引言跨越语言边界的桥梁 在现代软件开发中C和Python的协同工作已成为常态。C提供高性能计算开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考