基于BIO实现RPC框架
基于bio手写实现简单的rpc_java 手写一个bio-CSDN博客
RPC
RPC设计
RPC 的核心就是让客户端调用远程服务方法,就像调用本地方法一样。
- 服务端将自己的类注册到远程服务。
- 客户端通过注册中心获取到服务端地址。
- 客户端调用服务端地址,传入类名,调用方法、入参
- 服务端收到方法信息后,本地通过反射执行方法,获取结果返回给客户端。
- 客户端需要写一个需要调用的类,和服务端的类保持一致(方法名、入参类型、入参)。
- 客户端需要对这个类进行动态代理,实际访问的是该类的代理对象。
- 代理逻辑包括对获取方法信息(方法名、入参),然后调用远程服务,将远程服务返回结果返回。
- 客户端需要对这个类进行动态代理,实际访问的是该类的代理对象。
代理问题
RPC 的本质是让调用远程服务像调用本地方法一样简单。
调用者不关心内部实现,具体的远程调用由代理对象负责,这里就用到了代理模式。
序列化问题
在网络传输过程中,将对象变为二进制串传输。通过对象的序列化和反序列化实现。
通信问题
可以通过 BIO 进行网络传输。
注册中心
注册中心只有两种请求
- 服务注册
- 服务发现
将服务注册到注册中心,注册中心其实通过一个 Map 保存实例信息,维护 serviceName 和 serviceAddress 的关系。
java
//注册服务名,支持多实例
//注册加锁,查询不加
private static final Map<String, Set<RegisterServiceVo>> SERVICE_HOLDER = new HashMap<>();
服务端
- 启动时需要将自己注册到注册中心
- 提供基于反射调用自己方法的能力
客户端
从注册中心获取服务列表,获取服务真实地址。
添加远程服务接口。
javapublic interface IStockService { /** * 获取商品的库存 * @param skuId * @return */ long getStock(Integer skuId); }
基于远程服务接口进行 JDK 动态代理。
基于远程服务接口类,创建一个动态代理类并且放到 Spring 中。在使用的时候从 Spring 容器中获取该 Service,即可调用动态代理类的逻辑。
java@Configuration public class BeanConfig { @Autowired RpcClientFrame rpcClientFrame; /** * 注册远程服务接口 * 创建远程服务接口的代理对象,实现调用远程服务的逻辑 * @return */ @Bean public IStockService iStockService(){ return rpcClientFrame.getRemoteProxyObject(IStockService.class); } }
动态代理类的逻辑
- 获取远程服务真实地址。
- 使用反射获取远程服务类、方法、入参等信息。
- 调用远程服务。
java/** * 远程服务的代理对象,参数是客户端要调用的服务 */ public <T> T getRemoteProxyObject(final Class<?> serviceInterface) { //从注册中心获取服务真实地址 InetSocketAddress serviceRealAddress = serviceDiscoveryHandler.getServiceRealAddress(serviceInterface.getName()); //获取服务代理对象,由代理对象进行实际的网络调用 //对Class执行InvocationHandler的Invoke方法,即JDK动态代理 return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, new DynProxy(serviceInterface, serviceRealAddress)); }