客户端调用用服务端的实现
- 在客户端调用我们主要用到的技术是:代理+反射+socket通信+zookeeper
- 代理主要是动态代理,这里用来进行通信流程处理的。
- 反射主要用来在服务端处理那个服务类,那个方法,请求的参数信息进行发请求数据封装的。
- socket通信我们这里使用的netty搭建的,网上很多的,下篇服务端做点简单说明
- zookeeper这里主要放的是服务端提供服务暴漏的IP:端口。
节点名称主要是请求类的全路径(也就是服务名这里采用了类的全路径)。
数据格式如下:
request:: '/PINGPANG_REGIST_SERVER/com.pingpang.test.Test,F response:: v{'127.0.0.1:18868}
- 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(); } 复制代码
- 代理方法组装成请求的协议
服务地址这里是放在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(); } 复制代码
- 客户端的调用实例
客户端调用接口的时候是通过代理调用的
RpcFactoryBean<Test>rb=new RpcFactoryBean<>(Test.class); Test t=rb.getRpc(); System.out.println("结果"+t.add(1, 2)); 复制代码
效果
网络异常,图片无法展示
|