简单分析
RMI(远程方法调用)的过程:客户端与服务器同时有一套接口,但是只有服务器有实现这套接口的具体代码,客户端需要将必要的参数传送到服务器,服务器执行代码,将结果返回到客户端,一次远程方法调用结束。
编程思路
要实现这个功能我认识应该分为三部分:
- 接口的注册:将已有的接口注册到服务器,为了当客户端向服务器请求服务的时候,客户端能找到对应的服务运行某个方法,得到结果,返回给客户端。
- 服务器的建立:建立服务器。
- 客户端的建立:建立客户端,客户端是知道接口的。
代码实现
一:接口的注册
RpcBeanDefinition
有三个成员,并提供这三个成员的get和set方法
private Class<?> klass;
private Method method;
private Object object;
RpcBeanFactory
接口的一个工厂,将注册进来的接口存储到这个工厂里面,方便客户端请求服务时获取指定服务,返回结果
private final Map<String, RpcBeanDefinition> rpcBeanMap;
public RpcBeanFactory() {
rpcBeanMap = new HashMap<>();
}
void addRpcBean(String rpcBeanId, RpcBeanDefinition rpcBeanDefinition) {
RpcBeanDefinition rbd = rpcBeanMap.get(rpcBeanId);
if (rbd != null) {
return;
}
rpcBeanMap.put(rpcBeanId, rpcBeanDefinition);
}
RpcBeanDefinition getRpcBean(String rpcBeanId) {
return rpcBeanMap.get(rpcBeanId);
}
RpcBeanRegistry
提供三种注册接口的方式,将传进来的接口放到Factory的Map中
private static void doRegister(RpcBeanFactory rpcBeanFactory, Class<?> interf, Object object) {
Method[] methods = interf.getDeclaredMethods();
for (Method method : methods) {
String rpcBeanId = String.valueOf(method.toString().hashCode());
System.out.println(method.getName() + "-rpcBeanId:" + rpcBeanId);
RpcBeanDefinition rpcBeanDefinition = new RpcBeanDefinition();
rpcBeanDefinition.setKlass(interf);
rpcBeanDefinition.setMethod(method);
rpcBeanDefinition.setObject(object);
rpcBeanFactory.addRpcBean(rpcBeanId, rpcBeanDefinition);
}
}
static void registInterface(RpcBeanFactory rpcBeanFactory, Class<?> interf, Object object) {
if (!interf.isAssignableFrom(object.getClass())) {
return;
}
doRegister(rpcBeanFactory, interf, object);
}
static void registInterface(RpcBeanFactory rpcBeanFactory, Class<?> interf, Class<?> implementClass) {
if (!interf.isAssignableFrom(implementClass)) {
return;
}
try {
doRegister(rpcBeanFactory, interf, implementClass.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
static void registInterface(RpcBeanFactory rpcBeanFactory, Class<?> klass) {
try {
doRegister(rpcBeanFactory, klass, klass.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
二:服务器的建立
RpcServer
private ServerSocket server;
private int port;
private volatile boolean goon;
private static long executorId;
private final RpcBeanFactory rpcBeanFactory;
private ThreadPoolExecutor threadPool;
public RpcServer() {
rpcBeanFactory = new RpcBeanFactory();
threadPool = new ThreadPoolExecutor(50, 100, 500, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>());
this.goon = false;
}
public void registryRpc(Class<?> klass) {
RpcBeanRegistry.registInterface(rpcBeanFactory, klass);
}
public void registryRpc(Class<?> interf, Object object) {
RpcBeanRegistry.registInterface(rpcBeanFactory, interf, object);
}
public void registryRpc(Class<?> interf, Class<?> implementClass) {
RpcBeanRegistry.registInterface(rpcBeanFactory, interf, implementClass);
}
public void startRpcServer() throws Exception {
if (this.port == 0) {
throw new PortNotDefinedException();
}
this.server = new ServerSocket(port);
this.goon = true;
new Thread(this, "RPC_SERVER").start();
}
@Override
public void run() {
while (goon) {
try {
Socket rpcClient = server.accept();
new RpcServerExecutor(rpcClient, this, threadPool, ++executorId);
} catch (IOException e) {
goon = false;
e.printStackTrace();
}
}
stopRpcServer();
}
RpcServerExecutor
从客户端接收id、参数,反射机制执行方法,将结果用Gson转换成字符串返回给客户端
private Socket socket;
private RpcServer rpcServer;
private ThreadPoolExecutor threadPool;
private DataInputStream dis;
private DataOutputStream dos;
public RpcServerExecutor(Socket socket, RpcServer rpcServer, ThreadPoolExecutor threadPool, long threadId) throws IOException {
this.socket = socket;
this.rpcServer = rpcServer;
this.dis = new DataInputStream(this.socket.getInputStream());
this.dos = new DataOutputStream(this.socket.getOutputStream());
this.threadPool = threadPool;
this.threadPool.execute(this);
}
@Override
public void run() {
try {
Gson gson = (new GsonBuilder()).create();
String rpcBeanId = dis.readUTF();
rpcBeanId = rpcBeanId.substring(1, rpcBeanId.lastIndexOf("\""));
RpcBeanDefinition rpcBeanDefinition = rpcServer.getRpcBeanFactory().getRpcBean(rpcBeanId);
Method method = rpcBeanDefinition.getMethod();
Object object = rpcBeanDefinition.getObject();
String paraJson = dis.readUTF();
Object[] para = gson.fromJson(paraJson, Object[].class);
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] parameters = new Object[parameterTypes.length];
for (int i = 0; i < para.length; i++) {
parameters[i] = gson.fromJson(para[i] + "", parameterTypes[i]);
}
Object result = method.invoke(object, parameters);
dos.writeUTF(gson.toJson(result));
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseableUtil.close(dis, dos, socket);
}
}
三、客户端的建立
ClientServer
获取代理,启动rpcExecutor
private RpcClientExecutor rpcClientExecutor;
public RpcClient(String rpcServerIp, int rpcServerPort) {
this.rpcClientExecutor =
new RpcClientExecutor(rpcServerIp, rpcServerPort);
}
@SuppressWarnings("unchecked")
public <T> T jdkProxy(Class<?> klass) {
return (T) Proxy.newProxyInstance(
klass.getClassLoader(),
new Class<?>[]{ klass },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String rpcBeanId = String.valueOf(method.toString().hashCode());
Class<?> returnType = method.getReturnType();
return rpcClientExecutor.rpcExecutor(rpcBeanId, args, returnType);
}
}
);
}
RpcClientExecutor
将methodId跟参数数组发到服务器端,得到服务器端传过来的结果
private String rpcServerIp;
private int rpcServerPort;
public RpcClientExecutor(String rpcServerIp, int rpcServerPort) {
this.rpcServerIp = rpcServerIp;
this.rpcServerPort = rpcServerPort;
}
@SuppressWarnings("unchecked")
<T> T rpcExecutor(String rpcBeanId, Object[] parameters, Class<?> returnType) throws Exception {
Socket socket = new Socket(rpcServerIp, rpcServerPort);
Gson gson = (new GsonBuilder()).create();
System.out.println("rpcBeanId:" + gson.toJson(rpcBeanId));
System.out.println("parameters:" + gson.toJson(parameters));
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(gson.toJson(rpcBeanId));
dos.writeUTF(gson.toJson(parameters));
DataInputStream dis = new DataInputStream(socket.getInputStream());
String str = dis.readUTF();
Object result = gson.fromJson(str, returnType);
CloseableUtil.close(dos, dis, socket);
return (T)result;
}
测试
测试接口
public interface IUserAction {
UserModel getUserById(String id);
UserModel getUser(UserModel user);
UserModel getUser(UserModel user, UserModel user2);
List<UserModel> getUserList();
}
接口实现
@Override
public UserModel getUserById(String id) {
UserModel user = new UserModel();
user.setId(id);
user.setName("张三");
user.setSex(true);
return user;
}
@Override
public List<UserModel> getUserList() {
List<UserModel> userList = new ArrayList<>();
UserModel user = new UserModel();
user.setId("12345678");
user.setName("张三");
user.setSex(true);
userList.add(user);
user = new UserModel();
user.setId("87654321");
user.setName("李四");
user.setSex(false);
userList.add(user);
return userList;
}
@Override
public UserModel getUser(UserModel user) {
return user;
}
@Override
public UserModel getUser(UserModel user, UserModel user2) {
System.out.println("userModel:" + user);
return null;
}
UserModel
private String id;
private String name;
private boolean sex;
private UserModel next;
ClientTest
public static void main(String[] args) {
RpcClient rpcClient = new RpcClient("127.0.0.1", 54189);
IUserAction proxy = rpcClient.jdkProxy(IUserAction.class);
UserModel user2 = new UserModel();
user2.setName("哈哈哈");
UserModel user = new UserModel();
user.setName("哈哈哈");
user2.setNext(user);
UserModel model = proxy.getUser(user2, user2);
System.out.println(model);
}
ServerTest
public static void main(String[] args) {
RpcServer rpcServer = new RpcServer();
rpcServer.setPort(54189);
rpcServer.registryRpc(IUserAction.class, UserActionImpl.class);
try {
rpcServer.startRpcServer();
} catch (Exception e) {
e.printStackTrace();
}
}
结果
parameters:[{"name":"哈哈哈","sex":false,"next":{"name":"哈哈哈","sex":false}},{"name":"哈哈哈","sex":false,"next":{"name":"哈哈哈","sex":false}}]
null