java rpc

参拷:http://jbm3072.iteye.com/blog/1088102

 

目标:让客户端调用远程机器(不同JVM上)的方法.

技术:RPC(Remote Process Call远程过程调用)

优点:使用RPC,可以像使用本地的程序(本地JVM)一样使用远程服务器上的程序。使用RPC的好处是简化了远程服务访问。提高了开发效率。

做法:在分发代码时,只需要将接口分发给客户端使用,在客户端看来只有接口,没有具体类实现。这样保证了代码的可扩展性和安全性。

基础:Java反射机制,动态代理,Java IO/NIO/Socket

 

1:首先介绍被调用的接口与具体类

1):它在服务端与客户端都有一份

 

package org.jy.rpc.op;

public interface MyList {
    void add(String s);
    int getSize();
}

 2):具体实现,只在服务器有一份

 

 

package org.jy.rpc.op;

import java.util.ArrayList;
import java.util.List;

public class MyListImpl implements MyList {
	List list=new ArrayList();
	@Override
	public void add(String s) {
		list.add(s);
	}
	@Override
	public int getSize() {
		return list.size();
	}
}

 2:rpc服务器与客户端通信用来传递参数的类

 

1)承载参数的类

 

package org.jy.rpc.protocal;

import java.io.Serializable;
import java.util.Arrays;
/**
 * 用于服务器与客户端的消息传递
 * @author Lenovo
 *
 */
public class Invocation implements Serializable {
	private static final long serialVersionUID = 1L;

	private Class interfaces; // 接口类
	private Method method; // 方法
	private Object[] params; // 参数
	private Object result; // 返回值

	public Object getResult() {
		return result;
	}

	public void setResult(Object result) {
		this.result = result;
	}

	public Class getInterfaces() {
		return interfaces;
	}

	public void setInterfaces(Class interfaces) {
		this.interfaces = interfaces;
	}

	public Method getMethod() {
		return method;
	}

	public void setMethod(Method method) {
		this.method = method;
	}

	public Object[] getParams() {
		return params;
	}

	public void setParams(Object[] params) {
		this.params = params;
	}

	@Override
	public String toString() {
		return interfaces.getName() + "." + method.getMethodName() + "("
				+ Arrays.toString(params) + ")";
	}

}

 2):方法类(我认为可以不用它)

 

package org.jy.rpc.protocal;

import java.io.Serializable;
/**
 * 用来存放方法名及参数类型
 * @author Lenovo
 */
public class Method implements Serializable{
	private static final long serialVersionUID = 1L;
	
	private String methodName;  //方法名称
	private Class[] params;      //参数类型
	public Method(String name, Class<?>[] parameterTypes) {
		this.methodName = name;
		this.params = parameterTypes;
	}

	public String getMethodName() {
		return methodName;
	}

	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}

	public Class[] getParams() {
		return params;
	}

	public void setParams(Class[] params) {
		this.params = params;
	}
}

 3:服务器端类

1)服务器入口

package org.jy.rpc;

import org.jy.rpc.op.MyList;
import org.jy.rpc.op.MyListImpl;
import org.jy.rpc.support.RPCServer;
import org.jy.rpc.support.Server;

public class Main {
	public static void main(String[] args) {
		// 创建服务器
		Server server = new RPCServer();
		// 注册可被调用的类
		server.register(MyList.class, MyListImpl.class);
		// 启动服务监听
		server.start();
	}
}

 2)服务类接口

package org.jy.rpc.support;

import org.jy.rpc.protocal.Invocation;

public interface Server {
	public void stop();
	public void start();
	public void register(Class interfaceDefiner,Class impl); //注册接口与具体实现
	public void call(Invocation invo);   //方法调用
	public boolean isRunning();
	public int getPort();
}

 3)服务类(主要就是跟据传来的接口名找到具体实例,利用反射调用方法返回结果)

package org.jy.rpc.support;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.jy.rpc.protocal.Invocation;

public class RPCServer implements Server {
	private int port = 20382;
	private Listener listener;
	private boolean isRuning = true;

	public void setRuning(boolean isRuning) {
		this.isRuning = isRuning;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	private Map<String, Object> serviceEngine = new HashMap<String, Object>(); // 存放接口名称与具体实例

	@Override
	public void call(Invocation invo) {
		Object obj = serviceEngine.get(invo.getInterfaces().getName());// 得到具体实现
		if (obj != null) {
			try {// 类存在反射方法
				Method m = obj.getClass().getMethod(
						invo.getMethod().getMethodName(),
						invo.getMethod().getParams());
				Object result = m.invoke(obj, invo.getParams());
				invo.setResult(result);
			} catch (Throwable th) {
				th.printStackTrace();
			}
		} else {
			throw new IllegalArgumentException("has no these class");
		}
	}

	@Override
	public void register(Class interfaceDefiner, Class impl) {
		try {
			this.serviceEngine.put(interfaceDefiner.getName(),
					impl.newInstance());
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}
	@Override
	public void start() {
		System.out.println("启动服务器");
		listener = new Listener(this);
		this.isRuning = true;
		listener.start();
	}
	@Override
	public void stop() {
		this.setRuning(false);
	}
	@Override
	public boolean isRunning() {
		return isRuning;
	}
}

 4):监听类(主要用来开启socker监听,接收返回Invocation )

package org.jy.rpc.support;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.jy.rpc.protocal.Invocation;

public class Listener extends Thread {
	private ServerSocket socket;
	private Server server;

	public Listener(Server server) {
		this.server = server;
	}
	@Override
	public void run() {
		System.out.println("启动服务器中,打开端口" + server.getPort());
		try {
			socket = new ServerSocket(server.getPort());
		} catch (IOException e1) {
			e1.printStackTrace();
			return;
		}
		while (server.isRunning()) {
			try {
				System.out.println("等待请求");
				Socket client = socket.accept();
				System.out.println("请求到来");
				ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
				Invocation invo = (Invocation) ois.readObject();
				System.out.println("远程调用:" + invo);

				server.call(invo);
				
				ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
				oos.writeObject(invo);
				oos.flush();
				oos.close();
				ois.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		try {
			if (socket != null && !socket.isClosed())
				socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 4:客户端

1)入口类

package org.jy.rpc;

import org.jy.rpc.op.MyList;

public class MainClient {
	public static void main(String[] args) {
		MyList proxy = RPC.getProxy(MyList.class, "127.0.0.1", 20382);
		proxy.add("gbz");
		System.out.println(proxy.getSize());
	}
}

 2):客户端的数据传送类(就是连接远程的socket,传参数,等返回)

package org.jy.rpc.support;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import org.jy.rpc.protocal.Invocation;

public class Client {
	private String host;
	private int port;
	private Socket socket;
	private ObjectOutputStream oos;
	private ObjectInputStream ois;

	public String getHost() {
		return host;
	}


	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}
	public void setPort(int port) {
		this.port = port;
	}

	public Client(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void init() throws UnknownHostException, IOException {
		socket = new Socket(host, port);
		oos = new ObjectOutputStream(socket.getOutputStream());
	}

	public void invoke(Invocation invo) throws UnknownHostException, IOException, ClassNotFoundException {
		init();
		System.out.println("写入数据");
		oos.writeObject(invo);
		oos.flush();
		ois = new ObjectInputStream(socket.getInputStream());
		
		Invocation result = (Invocation) ois.readObject();
		
		invo.setResult(result.getResult());
	}

}

 3):动态代理(产生具体类的代理类,调用代理类方法时执行invoke方法,它会通过客户端的socket调用服务器的具体实例的方法

package org.jy.rpc;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.jy.rpc.protocal.Invocation;
import org.jy.rpc.support.Client;


public class RPC {
	public static <T> T getProxy(final Class<T> clazz,String host,int port) {
		
		final Client client = new Client(host,port);
		InvocationHandler handler = new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				Invocation invo = new Invocation();
				invo.setInterfaces(clazz);
				invo.setMethod(new org.jy.rpc.protocal.Method(method.getName(),method.getParameterTypes()));
				invo.setParams(args);
				client.invoke(invo);   //调用远程服务器的方法
				return invo.getResult();
			}
		};
		T t = (T) Proxy.newProxyInstance(RPC.class.getClassLoader(), new Class[] {clazz}, handler);
		return t;
	}
}	

 

你可能感兴趣的:(java)