资讯详情

Spring Boot集成jsonrpc4j实现JSON-RPC服务端实战指南

📅 2026/9/10 0:31:24 | 华诺云谱 👁 阅读
Spring Boot集成jsonrpc4j实现JSON-RPC服务端实战指南
简介面向Java SpringBoot开发者的JSON-RPC服务端示例工程演示如何通过HTTP与JSON组合完成远程过程调用适合在微服务架构、前后端分离项目中需要为移动端或跨语言系统提供轻量级RPC接口的技术人员。RAR压缩包共26个文件大小约55KB主要包含5个Java源文件、5个class编译文件、4个properties配置、2个xml配置另有Maven wrapper、jar包及工程描述文件整体结构为标准Maven工程导入IDE后可直接运行、快速理解各模块职责。已有297人学习该内容示例以multiplier方法演示请求与响应完整格式客户端发送包含id、jsonrpc、method、params的JSON报文服务端解析后返回result结果。读者可从源码中掌握SpringBoot环境下JSON-RPC服务的搭建方式、注解配置与报文约定与常见REST接口对比能更清楚理解轻量级远程调用在参数传递和结果返回上的设计思路并据此扩展出加法、字符串处理等自定义方法。 如果你的服务端需要面向一台只会说 JSON-RPC 协议的设备或者想把内网几个服务之间的接口从 REST 改造成更偏动作调用的风格那在 Spring Boot 里搭一个 jsonrpc server 就是一个很现实的需求。我最近在处理设备数据采集网关时设备端只认可 JSON-RPC 2.0后端是标准的 Spring Boot 2.x 微服务所以踩了一圈协议和框架的坑。这篇文章就记录我自己的接入过程和取舍思路尽量把代码、排查方法都写清楚适合已经熟悉 Spring Boot 基础开发、突然要对接 JSON-RPC 客户端的人参考。1. 为什么要单独做一个 JSON-RPC Server1.1 JSON-RPC 和 REST 到底差在哪JSON-RPC 2.0 是一种非常轻量的远程调用协议请求和响应都是 JSON 对象格式标准固定。一个典型的请求是这样的{ jsonrpc: 2.0, method: device.execute, params: { command: reboot, payload: { slot: 1 } }, id: 1001 }响应也类似{ jsonrpc: 2.0, result: ok, id: 1001 }而 REST 是以资源为中心用 URL 和 HTTP method 表达“对资源做什么”。JSON-RPC 是用 method 字段表达“调用哪个方法”params 带参数id 关联请求和响应。这个差异决定了它更适合动作型业务。如果业务场景是“下发指令”“执行任务”“订阅事件”用 REST 往往需要强行造资源比如 POST /commands、POST /executions方法一多就麻烦。JSON-RPC 里 method 直接叫device.execute、job.start语义清楚省掉一层资源建模的功夫。1.2 什么场景下我会选 JSON-RPC 而不是 REST先说设备接入。设备端资源有限只需要按固定格式发 JSON 和收 JSON不关心 HTTP 语义把 REST 那一套复杂的状态码、缓存、幂等概念丢给设备端只会增加成本。第二种是内部服务之间的动作调用比如运维平台向业务服务发指令或者定时任务中心触发某个执行器这类调用本质上就是“告诉远端做一件事”不是“对资源做增删改查”。第三种是需要通知和批量请求的场景因为 JSON-RPC 原生定义了 notification没有 id 的请求和批量请求请求体是数组。如果你的对外接口涉及浏览器直接访问、CORS、资源版本管理那肯定还是 REST。所以不是要替代 REST而是在特定场景下更顺手。1.3 社区里可用的 Spring Boot 方案Spring Boot 本身没有内置 JSON-RPC社区最常用的是 jsonrpc4j。它把 JSON-RPC 协议解析、异常映射都处理好了通过注解就能暴露服务。另一个选择是手写 Controller因为协议本身不算复杂核心代码三五十行也能写完但要在参数绑定、异常对象、批量请求这些边界上多花功夫。还有一种就是基于 Netty 或 WebSocket 做长连接 JSON-RPC适合设备主动上报场景但没必要作为起步方案。大部分人第一次落地我建议直接上 jsonrpc4j先把链路跑通后面真有特殊需求再换手写也不迟。2. 搭一个最小可用的服务端2.1 引入依赖直接用 Maven 加依赖我用的版本是 1.6.2dependency groupIdcom.github.briandilley/groupId artifactIdjsonrpc4j/artifactId version1.6.2/version /dependency注意jsonrpc4j 1.6.x 依赖的是 javax.servlet所以 Spring Boot 2.x 可以直接用如果是 Spring Boot 3.xservlet 全部换成了 jakarta 命名空间这个版本是用不了的。这也是我目前没在主项目上升 Boot 3 的原因之一。如果你一定要在 Boot 3 上用要么找适配版本要么自己封装协议。这个建议大家提前确认好不然启动时会碰到各种 ClassNotFoundException。2.2 定义接口和实现类定义一个接口加JsonRpcService注解指定对外路径JsonRpcService(/deviceService) public interface DeviceService { JsonRpcMethod(device.execute) String execute(JsonRpcParam(command) String command, JsonRpcParam(payload) MapString, Object payload); }实现类Service public class DeviceServiceImpl implements DeviceService { Override public String execute(String command, MapString, Object payload) { // 这里写你的业务逻辑 return ok; } }为什么推荐用JsonRpcParam把参数名写死因为 JSON-RPC 的 params 可以是位置参数数组也可以是命名参数对象。同一个方法有的客户端传数组有的客户端传对象如果让库去猜顺序很容易出错。显式命名后接口实现可以固定按名取参对调用方也更友好。2.3 用 AutoJsonRpcServiceImplExporter 暴露路由添加一个配置类Configuration public class JsonRpcConfig { Bean public AutoJsonRpcServiceImplExporter autoJsonRpcServiceImplExporter() { AutoJsonRpcServiceImplExporter exporter new AutoJsonRpcServiceImplExporter(); return exporter; } }这个组件会扫描 Spring 容器中带JsonRpcService接口的实现为每个接口注册一个 JSON-RPC 端点挂到 Spring MVC 的 DispatcherServlet 上。启动应用后客户端直接 POST 到应用根路径 /deviceService就能调用。如果项目有 context-path要把 context-path 也算进去。2.4 配置项调整我见过有些工程会自定义 ObjectMapper、超时时间。如果只是基础使用默认配置够了但有一个建议把 Jackson 的FAIL_ON_UNKNOWN_PROPERTIES关掉。JSON-RPC 客户端可能会额外传版本号、签名之类的字段服务端不应该因为识别不了就直接报参数错误。在 application.yml 配置spring: jackson: deserialization: fail-on-unknown-properties: false这个配置对 jsonrpc4j 同样生效因为底层就是同一套 Jackson。3. 处理协议细节与边界情况3.1 请求、响应格式与参数绑定JSON-RPC 2.0 请求对象里 method 是必须的params 可选id 可选。如果 id 缺失表示这是一个通知服务端处理完不用返回。jsonrpc4j 已经处理了这些语义但如果你自己写 Controller需要特别注意通知请求的响应不能返回给客户端否则客户端在等待 id 时会表现异常。参数绑定有两种情况。接口方法签名里有MapString, Object这种复杂类型JSON-RPC 客户端传的是字符串或数字Jackson 会自动转换。如果参数声明成具体 DTO 对象方法内直接拿到对象这时 DTO 字段名必须和 params 里的键一致否则会绑定空值。我自己踩过一个小坑客户端那边用下划线命名device_name服务端 DTO 用驼峰deviceName最终拿到的是 null。后来统一在 DTO 上加了JsonProperty才解决。3.2 异常码映射与自定义错误响应JSON-RPC 2.0 定义了保留错误码服务端最好遵循错误码含义-32700解析错误请求体不是合法 JSON-32600无效请求JSON 结构不符合协议-32601方法不存在-32602参数不合法-32603内部错误-32000 ~ -32099服务端自定义错误jsonrpc4j 默认对业务异常基本都返回内部错误 -32603这对联调不太友好。我的做法是在实现类方法里捕获业务异常包装成自定义 RuntimeException再通过全局异常处理器或 ControllerAdvice 转成 JSON-RPC 错误对象。如果你手写 Controller直接在 invoke 的 catch 里返回对应 code 就行。总之不要把原始堆栈直接暴露给客户端客户端收到一长串堆栈没意义反而泄露实现细节。3.3 批量请求、通知与空参数批量请求是指请求体是 JSON 数组每个元素都是一个请求对象响应也必须是数组顺序可以不一致但必须带 id 对应。jsonrpc4j 是支持这个的但如果服务挂在网关后面网关可能对请求体大小有限制批量请求很容易触发 413。需要提前测试必要时调大请求体限制。空参数也是一个容易被忽略的点。如果方法没有参数客户端可能不传 params也可能传params:[]。解析时要做空判断否则容易 NPE。我习惯在写接口实现前先拿客户端真实请求体造一组测试数据覆盖空参数和 null 字段比上线后让客户来报 bug 强得多。4. 接入 Spring Security 与拦截器4.1 身份校验怎么设计JSON-RPC 服务一般也要做认证。最稳妥的是利用 Header 传 token因为 JSON-RPC 的 body 是协议数据硬塞 token 进去会污染参数。可以自定义一个 OncePerRequestFilter从 Authorization 或者约定的 X-Device-Token 解析 token放到 RequestContext 里设备端也可以加设备序列号做签名校验。在 Spring Security 的配置里把/deviceService/**这类路径纳入认证范围再按不同路径前缀区分客户端类型。如果多个 JSON-RPC 服务路径也要分别配置放行规则。有一点容易被忽略JSON-RPC 对同一个路径会有不同的 method安全和限流最好在 method 维度做而不是只看 URL。4.2 日志与审计JSON-RPC 的 method 在请求体里不像 REST 在 URL 上那么直观看出来所以请求日志尤其重要。建议加一个拦截器记录来源 IP、method、耗时对批量请求最好把每个子请求的 method 和结果也打出来。出问题时能快速定位是哪个调用失败。我习惯在 JSON-RPC Controller 入口记一行 debug出口记一行 info中间用 MDC 放 traceId。这样排查链路时能从前端请求一直看到后端日志不需要在多个服务之间反复翻时间戳。4.3 限流与性能保护如果 JSON-RPC 接口被外部批量调用一次请求可能包含几十个调用只在 Controller 上对总次数限流是不够的。需要在应用层按 method 维度做限流比如使用 Resilience4j 的 RateLimiter以 method 名作为 key。或者直接在网关层限制请求体大小和并发数。具体策略看业务但有一个原则不要把限流完全交给基础组件自己的调用链路上要能看清楚瓶颈。5. 高频实战问题与排查5.1 接口无法访问先检查路径组合最常见的问题是启动后 POST 路径直接 404。第一看 context-path第二看拦截器或过滤器第三看JsonRpcService注解路径有没有拼错。特别是项目里配了spring.mvc.servlet.path的时候会额外增加一层前缀。如果实在定位不了可以先注册一个临时映射打到 /test确认 Spring MVC 的路由本身没问题再回来查 JSON-RPC。5.2 LocalDateTime 序列化踩坑这是高频问题。如果接口参数或返回值里有 LocalDateTimeJSON-RPC 客户端又不是 Java很容易出现时间格式不一致。默认 Jackson 会序列化成 ISO 字符串但有的客户端只认时间戳有的只认yyyy-MM-dd HH:mm:ss。建议在 DTO 字段上统一使用JsonFormat(pattern yyyy-MM-dd HH:mm:ss)而不是只依赖全局配置。因为 JSON-RPC 是协议级别的接口时间格式是协议的一部分应该明确固定下来。5.3 用 curl 快速测试与调试用 curl 是最快的curl -X POST http://localhost:8080/deviceService \ -H Content-Type: application/json \ -d {jsonrpc:2.0,method:device.execute,params:{command:reboot,payload:{slot:1}},id:1}返回结果里要关注两个点id 是否原样返回error.code 是否在预设范围内。我建议连-32700这种坏 JSON 的请求也测一下验证解析错误处理是生效的。很多工程只测了正常路径结果一遇到协议层解析异常就暴露出 500 响应这种问题最好在联调前自己先发现。5.4 与 Feign、HttpClient 客户端对接如果另一个 Java 服务要调用这个 JSON-RPC 服务直接用 OkHttp 封装一个方法把请求体拼好、响应体解析成 JsonNode代码量不大。Feign 也可以但需要自定义 Decoder因为 Feign 默认按 REST 语义处理状态码和响应体不适合 JSON-RPC 这种“HTTP 始终 200、错误放 body”的协议。我一般用 OkHttp 简单封装反而更容易控制超时和重试。最后说一个我自己的习惯不管用 jsonrpc4j 还是手写 Controller我都会先定好一套错误码规范比如 -32000 到 -32099 哪些是参数错误哪些是设备不在线。协议本身不复杂真正让服务稳定的是边界情况处理。如果后面你有空还可以顺着这个思路扩展一个简单的 JSON-RPC 客户端封装整个调用链路会更统一。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。