java分布式调用入门 自定义基于反射 Scoket JKD动态代理 RPC框架
使用工具IDEA, Myeclipse
编写服务端接口 HelloService
服务端实现类
编写服务端的调用类
package whu;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class RpcFramework {
//注册开始方法
public static void export(Object service, Class interfaceClazz, int port) throws Exception {
if (service == null) {
throw new IllegalAccessException("service instance == null");
}
if (port < 0 || port > 65535) {
throw new IllegalAccessException("Invalid port " + port);
}
System.out.println("Export service " + service.getClass().getName() + " on port " + port);
//服务端socket
ServerSocket server = new ServerSocket(port);
//死循环达到不断监听 使用while(true)也一样
for (;;) {
final Socket socket = server.accept();//阻塞等待客户端连接
try {
new Thread(new Runnable() {//多线程
@Override
public void run() {
try {
try {
//获取客户端传来的流对象
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
try {
String interfaceName = input.readUTF();//获取客户端传来需要调用的接口名
String methodName = input.readUTF();//客户端传来需要调用的方法
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();//客户端传来需要调用的方法的参数类型
Object[] arguments = (Object[]) input.readObject();//调用方法的参数
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());//返回客户端的留流对象
try {
//判断客户端需要调用的接口在服务端是否存在
if (!interfaceName.equals(interfaceClazz.getName())) {
throw new IllegalAccessException("Interface wrong, export:" + interfaceClazz
+ " refer:" + interfaceName);
}
Method method = service.getClass().getMethod(methodName, parameterTypes);//通过反射获取服务端的方法
Object result = method.invoke(service, arguments);//执行服务端方法
output.writeObject(result);//返回给客户端
} catch (Throwable t) {
output.writeObject(t);
} finally {
output.close();
}
} finally {
input.close();
}
} finally {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();//开启线程
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
我这里是直接传入一个对象 你们也可以写一个map用来注册多个对象
服务端启动类
package whu;
public class out {
public static void main(String[] args) throws Exception {
HelloService service = new HelloServiceImpl();
RpcFramework.export(service, HelloService.class, 9000);
}
}
客户端调用类
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;
public class Rpcfrowd {
/**
* @param args
*/
@SuppressWarnings("unchecked")//屏蔽黄线
public static <T> T refer(final Class<T> interfaceClass, final String host, final int port) throws Exception {
//System.out.println("Get remote service " + interfaceClass.getName() + " from server " + host + ":" + port);
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] { interfaceClass },
new InvocationHandler() {//jdk 动态代理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Socket socket = new Socket(host, port);//建立客户端socket 传入服务端ip 和端口
System.out.println("socket通过");
try {
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());//向服务端写入流对象
try {
output.writeUTF(interfaceClass.getName());//需要调用的接口名
output.writeUTF(method.getName());//需要调用的方法名
output.writeObject(method.getParameterTypes());//需要调用的参数类型
output.writeObject(args);//需要调用的参数
System.out.println("发送成功");
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());//接收服务端的返回信息
try {
Object result = input.readObject();//接收服务端的返回信息
System.out.println("接收成功"+result);
if (result instanceof Throwable) {
throw (Throwable) result;
}
return result;//返回
} finally {
input.close();
}
} finally {
output.close();
}
} finally {
socket.close();
}
}
});
}
}
注意第一个return是返回 生成的代理类对象 第二个是返回调用方法的返回值
客户端启动类
import whu.HelloService;
public class clid {
public static void main(String[] args) throws Exception {
HelloService service = (HelloService)Rpcfrowd.refer(Class.forName("whu.HelloService"), "127.0.0.1", 9000);
String result = service.hello("rod---");
System.out.println(result);
}
}
运行服务端启动类
运行客户端启动类
简单的rpc远程调用就实现了 这里提一下服务端需要接口和实现类 客户端只需要接口就行