Java简单的RPC实现(一)
RPC使用java最基本的,传输层使用Socket,序列化使用Serializable,java 动态代理模式,但是未实现消息注册等相关信息
大道至简
server端
package com.rpc.entity; import java.io.Serializable; public class RpcObject implements Serializable{ private static final long serialVersionUID = 1L;
private Class<?> c;
private String methodName;
private Object[] args; public RpcObject() { } public RpcObject(Class<?> c, String methodName, Object[] args) {
this.c = c;
this.methodName = methodName;
this.args = args;
} public Class<?> getC() {
return c;
} public void setC(Class<?> c) {
this.c = c;
} public String getMethodName() {
return methodName;
} public void setMethodName(String methodName) {
this.methodName = methodName;
} public Object[] getArgs() {
return args;
} public void setArgs(Object[] args) {
this.args = args;
}
}
ConfMonitor
package com.rpc.server; import java.util.HashMap;
import java.util.Map; import com.rpc.service.impl.HelloImpl; /**
* 模拟配置,实际的框架中大部分都是使用xml进行配置的,比如Hessian是配置在web.xml的servlet属性里的
* @author cdwangzijian
*
*/
public class ConfMonitor {
@SuppressWarnings("rawtypes")
public static Map<String, Class> conf = new HashMap<String, Class>(); static {
conf.put("com.rpc.service.IHello", HelloImpl.class);
}
}
RpcThread
package com.rpc.server; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket; import com.rpc.entity.RpcObject; public class RpcThread extends Thread { private Socket s; public RpcThread(Socket s) {
this.s = s;
} @Override
public void run() { ObjectInputStream is = null;
ObjectOutputStream os = null; try { is = new ObjectInputStream(s.getInputStream()); // 得到远程调用参数,包含了接口名,调用方法,方法参数
RpcObject rpcObject = (RpcObject) is.readObject(); System.out.println("Method:"+rpcObject.getMethodName()); // 构建接口的实现类,然后通过反射调用方法
Object o = getObject(rpcObject.getC());
System.out.println("class:"+rpcObject.getC()); Object reO = executeMethod(o, rpcObject.getMethodName(), rpcObject.getArgs()); // 输出返回值
os = new ObjectOutputStream(s.getOutputStream());
os.writeObject(reO);
os.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if(is!=null){
is.close();
} if(os!=null){
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} /**
* 通过反射技术执行方法,并返回返回值
* @param o
* @param methodName
* @param args
* @return
*/
private Object executeMethod(Object o, String methodName, Object[] args) {
Object objR = null;
Class<?>[] cs = new Class[args.length];
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
cs[i] = arg.getClass();
}
try {
Method m = o.getClass().getMethod(methodName, cs);
objR = m.invoke(o, args);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return objR;
} /**
* 根据接口名得到实例
* @param c
* @return
*/
private Object getObject(Class<?> c) {
Object o = null;
try { System.out.println("c.getName:"+c.getName()); o = ConfMonitor.conf.get(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return o;
}
}
StartUp
package com.rpc.server; import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket; /**
* RPC服务器启动
* @author cdwangzijian
*
*/
public class StartUp { public static final int port = 9001; public static void main(String[] args) {
exportRpc();
} /**
* 导出RPC接口
*/
private static void exportRpc() {
try {
ServerSocket ss = new ServerSocket(port);
while(true){
Socket s = ss.accept();
if(s!=null){
new RpcThread(s).start();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
HelloImpl
package com.rpc.service.impl; import com.rpc.service.IHello; public class HelloImpl implements IHello {
@Override
public String sayHello(String name) {
return "hello:" + name;
}
}
IHello
package com.rpc.service; public interface IHello {
String sayHello(String name);
}
客户端实现:
ProxyFactory
package com.zhy.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class ProxyFactory { @SuppressWarnings("unchecked")
public static <T> T create(Class<T> c, String ip, int port) { InvocationHandler handler = new RpcProxy(ip, port, c); return (T) Proxy.newProxyInstance(c.getClassLoader(),new Class[] {c},handler);
}
}
RpcProxy
package com.zhy.proxy; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.Socket; import com.rpc.entity.RpcObject; /**
* 客户端接口代理
* 当客户端接口方法被调用的时候,把方法名,方法参数作为参数。
* 传送给远程服务执行,然后获取返回值
* @author cdwangzijian
*
*/
public class RpcProxy implements InvocationHandler, Serializable{ private String ip;
private int port;
private Class<?> c; private static final long serialVersionUID = 1L; public RpcProxy(String ip, int port, Class<?> c) {
this.ip = ip;
this.port = port;
this.c = c;
} /**
* 动态代理类,当调用接口方法的时候转为调用此方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { // 用作返回值
Object o = null;
// 通过socket调用远程服务
Socket s = new Socket(ip, port); // 组装为一个保留了要调用的类,方法名及参数的对象,然后序列化之后传给远程
RpcObject rpcObject = new RpcObject(c, method.getName(), args); ObjectOutputStream os = null;
ObjectInputStream is = null; try{
os = new ObjectOutputStream(s.getOutputStream());
os.writeObject(rpcObject);
os.flush(); // 从远程得到返回结果
is = new ObjectInputStream(s.getInputStream());
o = is.readObject(); } catch (Exception e) {
e.printStackTrace(); } finally{ if(os!=null){
os.close();
} if(is!=null){
is.close();
} } return o;
} }
RpcClient
package com.zhy; import com.rpc.service.IHello;
import com.zhy.proxy.ProxyFactory; public class RpcClient {
public static void main(String[] args) { String ip = "localhost";
int port = 9001; IHello hello = ProxyFactory.create(IHello.class, ip, port); System.out.println(hello.sayHello("小明")); }
}
输出结果:
Java简单的RPC实现(一)的更多相关文章
- Java 简单的rpc 一
一,简单rpc 是基于Java socket 编程 ServerSocket serverSocket = new ServerSocket(9999); System.out.println(&qu ...
- Java 简单的RPC 实现
借用了网上某大神的例子.... 目录结构是这样的... RpcFramework 主要是两个方法.一个是暴露服务,一个为引用服务.暴露服务的主要作用是声明一个接口的实现类.可以通过socket 远程调 ...
- 分布式架构的基石.简单的 RPC 框架实现(JAVA)
前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...
- Java实现简单的RPC框架(美团面试)
一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...
- Java使用Netty实现简单的RPC
造一个轮子,实现RPC调用 在写了一个Netty实现通信的简单例子后,萌发了自己实现RPC调用的想法,于是就开始进行了Netty-Rpc的工作,实现了一个简单的RPC调用工程. 如果也有兴趣动手造轮子 ...
- 最简单的RPC框架实现
通过java原生的序列化,Socket通信,动态代理和反射机制,实现一个简单的RPC框架,由三部分组成: 1.服务提供者,运行再服务端,负责提供服务接口定义和服务实现类 2.服务发布者,运行再RPC服 ...
- Java自带RPC实现,RMI框架入门
Java自带RPC实现,RMI框架入门 首先RMI(Remote Method Invocation)是Java特有的一种RPC实现,它能够使部署在不同主机上的Java对象进行通信与方法调用,它是一种 ...
- 面试题思考:Java RMI与RPC,JMS的比较
RPC:(Remote Procedure Call) 被设计为在应用程序间通信的平台中立的方式,它不理会操作系统之间以及语言之间的差异. 支持多语言 RMI:(Remote Method Invo ...
- 如何实现一个简单的RPC
在如何给老婆解释什么是RPC中,我们讨论了RPC的实现思路. 那么这一次,就让我们通过代码来实现一个简单的RPC吧! RPC的实现原理 正如上一讲所说,RPC主要是为了解决的两个问题: 解决分布式系统 ...
随机推荐
- 一个CSV文件解析类
import java.io.BufferedReader; import java.io.FileReader; import java.util.ArrayList; import java.ut ...
- C++ 补遗
C++通过引用传递数组 数组形参可以声明为数组的引用.如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身. 在这种情况下,数组大小成为形参和实参类型的一部分(实参长度与形参长 ...
- Postgresql 創建觸發器,刪除觸發器和 禁用觸發器
CREATE OR REPLACE FUNCTION XF_VIP_AFUPD_WX() RETURNS trigger AS $$ DECLARE i_count integer; s_wx_ope ...
- DAC--使用DAC来导出数据库脚本
//============================================== //功能介绍:使用DAC来导出数据库脚本 //注意事项: //1.本程序涉及到的DLL有: // - ...
- Python 数据结构与算法——链表
#构造节点类 class Node(object): def __init__(self,data=None,_next=None): ''' self.data:为自定义的数据 self.next: ...
- IocPerformance 常见IOC 功能、性能比较
IocPerformance IocPerformance 基本功能.高级功能.启动预热三方面比较各IOC,可以用作选型参考. Lamar: StructureMap的替代品 Lamar 文档 兼容S ...
- Sql语句在SqlServer中创建数据库、表格并添加约束
通过Sql语句来创建数据库与架构 创建数据库 数据库的创建首先是要引用主数据库的,需要在master数据库的环境下进行创建.大致的语法如下: -- 使用master数据库 use master -- ...
- easyui-layout系列之表单一(2)
表单在我们的开发过程非常的常见,easyUI给我们提供了非常方便快捷的表单开发工具,使用熟练可以大大的提高后台开发速度,非常有必要熟练掌握. 1.Textbox-文本框 扩展自$.fn.validat ...
- 区别script中的type=”text/javascript”和language=”Javascript”
内容提要 在制作网页的时候,往往需要在页面中使用客户端能够运行的JS代码,因此,都需要添加引用.JS引用一般有type="text/javascript"和language=&qu ...
- 配置国内的maven仓库
MAVEN中央仓库 国内 配置Maven中央仓库路径的方法如下: 在Maven文件的conf目录中打开settings.xml文件 在文件中的servers节点和mirror节点中加入如下内容 华为云 ...