java原生rpc核心在于拦截器的invoke()中实现网络通信,而非代理本身;需手动完成请求构造、序列化、socket收发、响应解析及异常处理,并注意类加载器隔离、协议轻量设计、服务端反射执行与客户端超时重试机制。

Java原生方法拦截器本身不提供网络能力,它只是把本地调用“拦下来”,真正实现RPC靠的是在拦截逻辑里手动补全通信链路。核心不在代理怎么建,而在invoke()里怎么发请求、收响应、做序列化和错误处理。
动态代理是入口,不是全部
用Proxy.newProxyInstance()生成代理对象只是第一步。这个对象实现了你的服务接口,但所有方法调用都会被转发到InvocationHandler.invoke()。这里必须写实打实的网络逻辑——不能只打印日志或抛异常,要真正构造RpcRequest、编码、发Socket、等返回、解码、抛异常或返回结果。
- 别依赖“代理自动联网”:JDK动态代理不碰网络,不连注册中心,也不管序列化格式
-
method.getName()、args、method.getParameterTypes()都要取全,缺一不可 - 类加载器要隔离:服务端反序列化时若用错ClassLoader,会报
ClassNotFoundException
协议与序列化要轻量且可控
不用Protobuf或JSON也能跑通,Java原生ObjectOutputStream + ObjectInputStream足够教学和轻量场景使用,但要注意:
- 所有传输对象(如
RpcRequest、RpcResponse)必须实现Serializable - 统一用
UTF-8编码字符串字段,避免中文乱码 - 消息体前加4字节长度头,解决TCP粘包问题(哪怕只是简单
DataOutputStream.writeInt(len))
服务端用反射执行,但得管好生命周期
服务端收到字节流后,先反序列化出RpcRequest,再根据serviceName查本地注册表(比如一个ConcurrentHashMap<string object></string>),拿到真实实现对象,最后用Method.invoke()执行。
- 注册表要在服务启动时就填好,例如:
registry.put("com.example.HelloService", new HelloServiceImpl()) - 反射调用前检查
method是否在目标对象中可访问,避免IllegalAccessException - 捕获
InvocationTargetException并unwrap原始异常,否则客户端看到的是包装异常
客户端阻塞等待要带超时和重试
Socket通信默认是阻塞的,但没超时机制容易卡死。最简方案是在Socket上设置setSoTimeout(5000),并在invoke()里捕获SocketTimeoutException后决定是否重试一次。
- 不要用
while(true)无限重连,至少限制重试次数(如1次) - 连接失败(
IOException)和超时(SocketTimeoutException)应区分处理 - 响应反序列化失败时,应返回明确错误信息,而不是让客户端
NullPointerException
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











