RPC了解
RPC了解
定义
RPC = Remote Procedure Call 远程过程调用
简单来说像调用本地方法一样,调用远程服务器上的方法。
常见的RPC框架
Dubbo | 阿里巴巴 | 国内最流行,功能强大,集成 ZooKeeper |
---|---|---|
gRPC | 跨语言,高性能,使用 Protobuf 和 HTTP/2 | |
Thrift | Apache | Facebook 开源,支持多语言 |
Spring Cloud OpenFeign | Spring | 基于 HTTP 的轻量级 RPC |
RPC核心组件
组件 | 作用 |
---|---|
动态代理 | 让调用远程方法像调用本地方法一样 |
序列化/反序列化 | 把对象转成字节流在网络上传输(如 JSON、Protobuf、Hessian) |
网络通信 | 使用 TCP/HTTP 传输数据(如 Netty、OkHttp) |
服务发现 | 找到服务端的 IP 和端口(如 ZooKeeper、Nacos) |
负载均衡 | 多个服务实例时,选择哪个调用(如轮询、随机) |
为什么需要RPC
在单体应用中,所有代码在一个进程里,方法调用是“本地调用”。
但在微服务架构中:
- 用户服务、订单服务、支付服务……分布在不同服务器上
- 它们必须互相调用
- 如果每次都手动发 HTTP 请求,太麻烦!
实现原理
反射
Java 反射的实现依赖于 JVM 的类加载机制 和 运行时的元数据存储。
- 类加载过程
- 当 JVM 加载一个类时,会创建一个对应的
Class
对象。 - 这个
Class
对象包含了类的所有元信息:字段、方法、构造器、注解、父类、接口等。 - 这些信息存储在 JVM 的 方法区(Method Area) 或 元空间(Metaspace,JDK 8+)。
- 反射如何工作
Class.forName()
触发类加载,返回Class
实例。- 通过
Class
实例可以获取Field
、Method
、Constructor
等对象。 - 调用
invoke()
、set()
等方法时,JVM 会通过 JNI(Java Native Interface)调用底层 C++ 代码,动态执行对应的方法或字段操作。
静态代理
一个租房子问题,中介就是这个原理。
缺点代理需要手动创建,简单来说就是房主和中介都要实现租房接口,这个租房接口规定了租房的规范,然后消费者只用调用中介的方法就能实现中介的很多方法并且最终实际租房的时候还是走的房东的租房方法,只是多加了很多中介的额外方法。
但是每次想要租房都得自己手动new一个中介出来。
动态代理
主要了解JDK动态代理,这个动态代理无需导入jar包,然后步骤上还是先定义好租房接口,也就是租房规则,然后房主要实现接口,这里有个区别了,这里的中介是万能中介,能代理任何出租方,出租房屋,汽车什么都行,怎么实现呢?
这里需要有一个动态中介处理器xxxHandler,这个类要有真是的代理对象然后实现InvocationHandler接口实现invoke方法,这样就能反射了,invoke方法里面传入代理对象也就是房主,然后方法,也就是rent方法,然后就是方法调用传入的参数值,然后这个invoke方法里面调用房东的租房方法比如
- 定义公共接口:
UserService.java
1 | // 用户服务接口(规则) |
- 实现类:
UserServiceImpl.java
1 | // 真实的业务对象(被代理的对象) |
- 代理处理器:
LoggingInvocationHandler.java
1 | import java.lang.reflect.InvocationHandler; |
- 工具类:
ProxyFactory.java
(用于生成代理对象)
1 | import java.lang.reflect.Proxy; |
- 测试类:
Client.java
1 | public class Client { |
总结
动态代理利用反射的功能,实现了本地的动态调用,这样本地调用别的类的方法的时候就不用每次都new对象然后再去调用对象了,具体实现是首先有个接口来定义好规则,然后被代理对象和使用代理对象的人都要遵守这套规则,然后动态代理需要有个代理工厂类,这个类需要有被代理对象然后实现InvocationHandler这个接口,然后实现invoke方法,然后在invoke方法里面调用被代理对象的方法,这里使用到了反射的技巧,由于JVM加载类的时候会创建Class对象,然后这个对象里面包含了被代理类的所有信息,包括方法,然后我们调用invoke方法的时候就能不用new 被代理对象就能调用它的方法了,然后使用代理对象的类只需要new动态中介,然后通过 Proxy.newProxyInstance(...)
方法生成一个代理对象,这个代理对象实现了与目标对象相同的接口。之后就可以像调用普通对象一样调用这个代理对象的方法,而实际执行时会自动将方法调用转发到 InvocationHandler
的 invoke
方法中进行处理。
RPC的实现原理
1、首先是本地发起调用服务中的方法,然后传入参数
2、然后这个接口由于是外部的方法,本地是没有实现类的,那么就利用动态代理获取实现类。
首先,会在运行时生成一个代理对象Stub,然后在动态代理里面封装了请求,调用网络模块发送请求的方法,然后在发送请求的时候会首先序列化参数,然后利用Socket进行TCP连接或者利用Netty等技术来发送请求,最后收到信息最后反序列化。然后服务端知道了你要调用的方法和参数,利用反射来动态的调用方法,然后将结果序列化然后通过网络发送给客户端,最终在客户端通过反序列化得到需要的结果。