不能直接用 new proxyinstance() 生成远程接口代理,因为 jdk 动态代理仅支持 interface 且需本地实现类,而 rpc 调用远端、本地无实现,否则抛 illegalargumentexception 或空指针;必须用 proxy.newproxyinstance() 配合自定义 invocationhandler 将调用转为网络请求。

为什么不能直接用 new ProxyInstance() 生成远程接口代理
因为 JDK 动态代理只能代理 interface,且要求被代理对象存在本地实现类——而 RPC 的本质是“调用远端,本地连实现都没有”。强行套用会导致运行时抛 IllegalArgumentException: not an interface 或空指针。必须用 Proxy.newProxyInstance() 配合自定义 InvocationHandler,把方法调用转成网络请求。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 代理目标类型必须是纯接口(不能是 class),且所有方法需有明确的参数类型(避免泛型擦除后无法反序列化)
-
InvocationHandler#invoke()中要提取method.getName()、method.getParameterTypes()和实际参数值,封装为统一请求结构体 - 别在 handler 里直接发 Netty 请求——Netty 的
Channel.writeAndFlush()是异步的,需配合DefaultPromise或 CompletableFuture 拦截响应
Netty 客户端连不上服务端的三个高频原因
不是配置错端口就是 Channel 生命周期没管好。常见现象是 java.nio.channels.ClosedChannelException 或连接超时却无日志。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 检查服务端是否绑定了
0.0.0.0而非127.0.0.1,Docker 或防火墙常拦截回环外地址 - 客户端
Bootstrap必须复用同一个EventLoopGroup,每次 new 一个 group 会导致连接未释放、线程泄漏 - 别在
channelActive()里立即发请求——此时 pipeline 可能还没初始化完;改用channelFuture.addListener()确保 channel 就绪后再写入
ObjectEncoder 和 ObjectDecoder 为什么在生产环境必须禁用
它们依赖 JDK 默认序列化,性能差、体积大、不跨语言、有严重安全风险(反序列化 gadget 可触发任意代码执行)。线上报 java.io.InvalidClassException 或 CPU 突增 90% 很可能就是它。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 立刻换成
ProtobufEncoder/Decoder或JsonEncoder/Decoder(如 Jackson +HttpObjectEncoder变种) - 若坚持用 Java 序列化,至少重写
ObjectInputStream.resolveClass()做白名单校验,但不推荐 - 注意
ObjectDecoder构造函数第二个参数是最大长度,设太小会丢包,设太大易被攻击;RPC 场景建议 ≤ 4MB
服务端收到请求但不返回响应,大概率卡在编解码或线程模型
典型表现:客户端等 timeout,服务端日志停在 “received request”,后续无 writeAndFlush() 日志。不是业务逻辑卡死,就是 Netty 的线程调度出问题。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 确认 handler 是否加了
@ChannelHandler.Sharable—— 如果没加又注册到多个 channel,会因状态共享导致响应写错 connection - 避免在
channelRead()里做耗时操作(如 DB 查询、HTTP 调用),必须用eventLoop().submit()或单独线程池处理,否则阻塞 IO 线程 - 响应 write 前务必检查
ctx.channel().isActive(),TCP 断连后继续 write 会静默失败,需捕获exceptionCaught()中的IOException
真正难调的是跨线程回调和 Promise 状态竞争——比如异步业务结果回来时,原 ChannelHandlerContext 已不可用,得靠 requestId 关联并主动查找活跃 channel。这点多数人写到一半才意识到。










