一个最简单的RPC服务流程(二)

222 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情

理论在一个最简单的RPC服务流程已经介绍了,这里我们看下怎么打通实现。

这里主要介绍下客户端的调用

客户端调用用服务端的实现

  1. 在客户端调用我们主要用到的技术是:代理+反射+socket通信+zookeeper

  2. 代理主要是动态代理,这里用来进行通信流程处理的。

  3. 反射主要用来在服务端处理那个服务类,那个方法,请求的参数信息进行发请求数据封装的。

  4. socket通信我们这里使用的netty搭建的,网上很多的,下篇服务端做点简单说明

  5. zookeeper这里主要放的是服务端提供服务暴漏的IP:端口。

节点名称主要是请求类的全路径(也就是服务名这里采用了类的全路径)。

数据格式如下:

request:: '/PINGPANG_REGIST_SERVER/com.pingpang.test.Test,F response:: v{'127.0.0.1:18868}

  1. zookeeper这里你可以剔除掉,用你的方式获取服务端暴露的服务

1. 本地的调用的时候我们是下面的方式

public int add(int a1,int a2){
 return a1+a2;
};
int sum=add(1,2);

1. 远程调用的实现

首先我们声明一个接口

public interface Test {
	public int add(int a,int b);
	public UserInfo findUserByName(String userName,String password);
	public List<UserInfo> findUserList();
	public void TestTask();
	public void TestTask2();
}
  1. 代理方法组装成请求的协议

服务地址这里是放在zookeeper上的数据格式为= ip:端口

这里采用的是系统的代理方式进行处理的

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		return threadPool.submit(new Callable<Object>() {
			@Override
			public Object call() throws Exception {
				try {
					if(null==client) {
						client = new NettyClient();
					}
					//获取IP地址开始
					logger.info("【通过zookeeper获取服务端地址开始】");
					SeverRegistry sr=SeverRegistry.getServerRegistry();
					List<String> ipList=sr.getServerPath(method.getDeclaringClass().getName());
					for(String str:ipList) {
						logger.info("服务名称{},地址{}",method.getDeclaringClass().getName(),str);
						ip=str.split(":")[0];
						port=Integer.valueOf(str.split(":")[1]);
					}
					logger.info("【通过zookeeper获取服务端地址结束】");
					//对数据信息进行组装
					String requestID = UUID.randomUUID().toString().replace("-", "");
					RequestBean request = new RequestBean();
					request.setClassName(method.getDeclaringClass().getName());
					request.setMethodName(method.getName());
					request.setParameters(args);
					request.setParameterTypes(method.getParameterTypes());
					request.setId(requestID);
					request.setIp(ip);
					request.setPort(port);
                                        
                                        //远程调用服务端
					Object result = client.send(request);
					ResponseBean response = (ResponseBean) result;
					if(-1==response.getCode()) {
						throw new Exception(response.getErrorMsg());
					}
					return response.getData();
				} catch (Exception e) {
					logger.error("调用失败:" + e.getMessage(), e);
					throw new Exception(e.getMessage());
				} finally {
					//关闭channel 客户端还可以复用
					  if(null!=client) { client.destroy(); client = null; }
					 
				}
			}
		}).get();
		 
	}
  1. 客户端的调用实例

客户端调用接口的时候是通过代理调用的

RpcFactoryBean<Test>rb=new RpcFactoryBean<>(Test.class);
Test t=rb.getRpc();
System.out.println("结果"+t.add(1, 2));

效果

image.png