服务端的实现
- 服务端用到的技术点:注解+反射+socket通信+zookeeper。
- 注解主要是扫描有那些提供服务的接口实现。
- 反射主要依靠远程客户端调用提供的类的信息进行反射调用。
- zookeeper的节点数据结构再上篇已经介绍了,主要是提供调用类的服务端IP+端口地址暴露
服务端提供的服务流程
- 定义一个注解
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Component public @interface RpcService { String version() default ""; } 复制代码
- 初始化扫描提供服务的类信息
Map<Strng, Object> beans = applicationContext.getBeansWithAnnotation(RpcService.class); 复制代码
- 根据扫描保存一些服务提供的类,和再zk上写入对外服务暴露的地址
数据格式如下:
request:: '/PINGPANG_REGIST_SERVER/com.pingpang.test.Test,F response:: v{'127.0.0.1:18868}
服务端提供的socket服务
- socket服务端,客户端主要是用netty实现的。
- 客户端服务端传输的协议这里主要借助了netty对象的序列化编解码,
下面是定义了一些序列化的工具
public enum CodeUtilEnum { HESSIAN(new HessianCodeUtil()), JSON(new JSONCodeUtil()), PROTOSTUFF(new ProtostuffCodeUtil()); public final MessageCodecUtil serializer; private CodeUtilEnum (MessageCodecUtil serializer) { this.serializer = serializer; } } 复制代码
这里主要是序列化的填充
//创建NIOSocketChannel成功后,在进行初始化时,将它的ChannelHandler设置到ChannelPipeline中,用于处理网络IO事件 protected void initChannel(SocketChannel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast(new IdleStateHandler(0, 0, 60)); //序列化定义 pipeline.addLast(new NettyDecoder(RequestBean.class, codeUtil)); //序列化定义 pipeline.addLast(new NettyEncoder(ResponseBean.class, codeUtil)); pipeline.addLast(businessGroup,handler); } 复制代码
没有用想象中的协议(定义协议的开头有多少位是整个协议的长度,后面是一大堆字符串类的;这里可能跟序列化有关系,后台屏蔽了协议的一些东西)
服务端的启动是借助springboot启动了一个线程。
服务端响应客户端的请求
- 服务端根据传递过来的信息进行服务调用,主要就是反射(传输过来的数据基本上就是反射需要的数据信息)
/** * 通过反射,执行本地方法 * @param request * @return * @throws Throwable */ private Object handler(RequestBean request) throws Throwable{ String className = request.getClassName(); Object serviceBean = serviceMap.get(className); if (serviceBean!=null){ Class<?> serviceClass = serviceBean.getClass(); String methodName = request.getMethodName(); Class<?>[] parameterTypes = request.getParameterTypes(); Object[] parameters = request.getParameters(); Method method = serviceClass.getMethod(methodName, parameterTypes); method.setAccessible(true); return method.invoke(serviceBean, parameters); //return method.invoke(serviceBean, getParameters(parameterTypes,parameters)); }else{ throw new Exception("未找到服务接口,请检查配置!:"+className+"#"+request.getMethodName()); } }