最近晚上没事,加上工作上要使用,所以开始自己学习RPC框架,目前写了一个基本的,便于理解,后续往里面添加内容。
**
服务提供方:
**
服务接口代码:
package zhm.rpc.server;
public interface IServer {
public String testMethod(String arg);
}
接口实现类:
/**
* rpcServerImpl.java
* zhm.rpc.server
* 2017年10月9日下午8:44:06
*
*/
package zhm.rpc.server;
/**
* @author zhuheming
* rpcServerImpl
* 2017年10月9日下午8:44:06
*/
public class rpcServerImpl implements IServer {
/* (non-Javadoc)
* @see zhm.rpc.server.IServer#testMethod(java.lang.String)
*/
@Override
public String testMethod(String arg) {
// TODO Auto-generated method stub
return "hello, "+arg;
}
}
反射类:
主要用于接收服务消费方发起的远程调用请求,得到method和args,就是方法和参数,再利用反射方式执行该方法,返回执行结果。
这里反射使用了commons.lang3包中的MethodUtils工具类实现。
/**
* serverReflect.java
* zhu.rpc.reflect
* 2017年10月9日下午9:24:47
*
*/
package zhu.rpc.reflect;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.commons.lang3.reflect.MethodUtils;
/**
* @author zhuheming
* serverReflect
* 2017年10月9日下午9:24:47
*/
public class ServerReflect implements Runnable{
private Object object;
private int port;
public ServerReflect(Object object,int port){
this.object=object;
this.port=port;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// TODO Auto-generated method stub
//新建连接
//SocketConnect sc=new SocketConnect();
//Socket socket=sc.connect("127.0.0.1", port);
try {
ServerSocket ss=new ServerSocket(port);
while(true){
try {
final Socket socket=ss.accept();
//建立输入
ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
try{
//得到方法名和参数列表
String method=ois.readUTF();
Object[] args=(Object[])ois.readObject();
System.out.print(method+" "+args.toString());
//反射得到对应方法的执行结果
Object resultObject=MethodUtils.invokeExactMethod(object, method, args);
ObjectOutputStream oos=new ObjectOutputStream(socket.getOutputStream());
try{
//返回结果
oos.writeObject(resultObject);
}catch(Exception e){
oos.writeObject(e);
e.printStackTrace();
}finally{
oos.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
ois.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
//private static Thread serverThread=new Thread();
//public void waittingServer(Class<T> serverClass,int port)
}
测试入口:
省得麻烦,直接使用8081端口,用一个Thread来运行等待服务消费端的调用。
/**
* test.java
* zhm.rpc.test
* 2017年10月9日下午10:18:33
*
*/
package zhm.rpc.test;
import zhm.rpc.server.IServer;
import zhm.rpc.server.rpcServerImpl;
import zhu.rpc.reflect.ServerReflect;
/**
* @author zhuheming
* test
* 2017年10月9日下午10:18:33
*/
public class testServer {
public static void main(String args[]) throws InterruptedException{
IServer is=new rpcServerImpl();
Thread serverThread=new Thread(new ServerReflect(is,8081));
serverThread.start();
serverThread.join();
}
}
**
服务消费方:
**
socket连接器,这里使用了一个连接接口IConnect,方便以后如果使用多种连接方式可以抽象
package zhm.rpc.connect;
import java.net.Socket;
/**
* socket连接器
* @author zhuheming
* socketConnet
* 2017年9月28日下午11:29:24
*/
public class SocketConnect implements IConnect {
@Override
public Socket connect(String host, int port) {
// TODO Auto-generated method stub
//判断输入参数
if(!"".equalsIgnoreCase(host)&&port!=0){
Socket socket=null;
try{
socket=new Socket(host,port);
}catch(Exception e){
e.getStackTrace();
}
return socket;
}else{
return null;
}
}
public void close(Object connectObject){
if(connectObject!=null){
try{
Socket socket=(Socket)connectObject;
socket.close();
}catch(Exception e){
e.getStackTrace();
}
}
}
}
服务消费方的动态代理实现:
思路是将服务提供方的IServer接口生成动态代理类,使用动态代理类执行执行IServer的接口方法时,会调用invoke方法,在invoke方法中,远程连接消费提供方,将方法名称和参数发送给服务提供方,由服务提供方返回执行结果。
/**
* cosumeProxy.java
* zhm.rpc.proxy
* 2017年9月29日上午12:03:30
*
*/
package zhm.rpc.proxy;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
import zhm.rpc.connect.SocketConnect;
/**
* @author zhuheming
* cosumeProxy
* 2017年9月29日上午12:03:30
*/
public class ConsumeProxy {
//匿名内部类方法实现需要调用,所以host和port需要为final
@SuppressWarnings("unchecked")
public static <T> T consume(Class<T> interfaceClass,final String host,final int port){
//先建立一个InvocationHandler接口的对象(实现内部方法)
//InvocationHandler invocationHandler=;
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass},new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
//建立连接
SocketConnect sc=new SocketConnect();
Socket socket=sc.connect(host, port);
//发送方法和参数
ObjectOutputStream ops=new ObjectOutputStream(socket.getOutputStream());
ops.writeUTF(method.getName());
ops.writeObject(args);
//接收返回
ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
Object getObject=ois.readObject();
return getObject;
}
});
//return null;
}
}
服务提供方给的服务接口
注意,实现是在服务提供方,消费方只有接口
package zhm.rpc.server;
public interface IServer {
public String testMethod(String arg);
}
服务消费方入口:
先生成代理类,再远程执行方法。
package zhm.rpc.test;
import zhm.rpc.proxy.ConsumeProxy;
import zhm.rpc.server.IServer;
public class Test {
//远程调用服务端的testMethod方法,客户端只有接口,没有方法实现。
public static void main(String args[]) throws InterruptedException{
Object obj= ConsumeProxy.consume(IServer.class, "127.0.0.1", 8081);
if(obj!=null){
System.out.println(obj.getClass().getInterfaces().toString());
//System.out.println(obj.toString());
System.out.println("not null!");
}else{
System.out.println("null!");
}
IServer rpc=(IServer)obj;
for(int i=0;i<100;i++){
System.out.println(rpc.testMethod(""+i));
Thread.sleep(1000);
}
}
}
好了,以上就是最简单的RPC远程执行框架,要想丰满起来,后续还要考虑很多,如自己实现序列化反序列化,软负载均衡,高可用NIO通讯方式,服务的解耦合IOC方式,以及服务治理,类似zk的服务发布等。
继续努力吧。