rmi即:远程方法调用(Remote Method Invocation)
在c/s模式下,客户端和服务端所侧重的东西是不一样的,客户端只需要发出请求和得到结果,而不需要知道这个请求是如何完成的。同时,为了保护软件的封装性和安全性,不能把一个事务的具体执行都放在客户端执行,只需要给一个接口,用户调用接口所给的方法,等待结果返回回来,这才是一个软件安全性的一个保障。这时候,rmi的出现就给了我们这个想法提供了强有力的支撑。
/**
* RMI服务器结点信息,存有RMI服务器的IP地址和端口号port
* @Author :漠殇
* @Data :Create in 11:20 2021/7/16
*/
public class NodeAddress {
private String ip;
private int port;
public NodeAddress() {
}
public NodeAddress(String ip, int port) {
this.ip = ip;
this.port = port;
}
String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
public class ArgumentMaker {
public static final Gson gson = new GsonBuilder().create();
private static Type mapType = new TypeToken<Map<String, String>>() {}.getType();
private Map<String, String> argMap;
public ArgumentMaker() {
this.argMap = new HashMap<String, String>();
}
public ArgumentMaker(String parameterString) {
this.argMap = gson.fromJson(parameterString, mapType);
}
public Object getParameter(String name, Class<?> type) {
String strValue = this.argMap.get(name);
return gson.fromJson(strValue, type);
}
public Object getParameter(String name, Type type) {
String strValue = this.argMap.get(name);
return gson.fromJson(strValue, type);
}
public ArgumentMaker add(String parameterName, Object parameterValue) {
this.argMap.put(parameterName, gson.toJson(parameterValue));
return this;
}
@Override
public String toString() {
return gson.toJson(this.argMap);
}
}
/**
* 一个远程调用方法的信息,执行类对象和方法
* @Author :漠殇
* @Data :Create in 9:45 2021/7/16
*/
public class RmiInterfaceDefinition {
private Class<?> klass;
private Object object;
private Method method;
RmiInterfaceDefinition() {
}
RmiInterfaceDefinition(Class<?> klass, Object object, Method method) {
this.klass = klass;
this.object = object;
this.method = method;
}
public Class<?> getKlass() {
return klass;
}
public void setKlass(Class<?> klass) {
this.klass = klass;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}
/**
* 所有需要远程调用的方法都存在与这个类的interfacePool中
* @Author :漠殇
* @Data :Create in 9:43 2021/7/16
*
*/
public class RmiInterfaceFactory {
private static final Map<String, RmiInterfaceDefinition> interfacePool;
static {
interfacePool = new HashMap<>();
}
public RmiInterfaceFactory() {
}
/**
* 初始化interfacepool,完成接口类与实现类的对应
* xml格式
* <interfaces>
* <interface interfaceName="" className=""></interface>
* </interfaces>
* @param mappingPath
*/
public void scanMethodMap(String mappingPath) {
try {
new XMLParser() {
@Override
public void dealElement(Element element, int index) throws Throwable {
String interfaceName = element.getAttribute("interfaceName");
String className = element.getAttribute("className");
byClassNamedealClass(interfaceName, className);
}
}.parseTag(XMLParser.newDocument(mappingPath), "interface");
} catch (XMLNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
/**
* 外面可以设置新的接口和他的实现类
* @param interfaceName
* @param className
* @throws Throwable
*/
public void addInterface(String interfaceName, String className) throws Throwable {
byClassNamedealClass(interfaceName, className);
}
/**
* 判断接口interfaceName是否符合规定和类className是否是接口的实现类
* @param interfaceName
* @param className
* @throws Throwable
*/
private void byClassNamedealClass(String interfaceName, String className) throws Throwable{
Class<?> interfaze = Class.forName(interfaceName);
Class<?> klass = Class.forName(className);
if (!interfaze.isInterface()) {
new Exception("[ " + interfaze.getName() + "] : NOT is interface");
}
//判断klass是否实现了这个interfaze接口
if (interfaze.isAssignableFrom(klass)) {
new Exception("[" + interfaze.getName() + "] : NOT is " + "[" + klass.getName() + "] Assignable");
}
Object object = klass.newInstance();
creatRealInterfaceMethod(interfaze, klass, object);
}
/**
* 完成真正的一个接口对应一个实现类方法的填充。
* @param interfaze
* @param klass
* @param object
* @throws NoSuchMethodException
*/
private void creatRealInterfaceMethod(Class<?> interfaze, Class<?> klass, Object object) throws NoSuchMethodException {
Method[] methods = interfaze.getDeclaredMethods();
for (Method interfaceMethod : methods) {
//creat key
String key = String.valueOf(interfaceMethod.toString().hashCode());
//找到接口方法对应类的真正方法
String methodName = interfaceMethod.getName();
Class<?>[] parameterTypes = interfaceMethod.getParameterTypes();
Method method = klass.getDeclaredMethod(methodName, parameterTypes);
//生成这个Method的Definition,放入方法池
RmiInterfaceDefinition rmiInterfaceDefinition = new RmiInterfaceDefinition(klass, object, method);
RmiInterfaceFactory.interfacePool.put(key, rmiInterfaceDefinition);
}
}
public static RmiInterfaceDefinition getMethod(String key) {
return RmiInterfaceFactory.interfacePool.get(key);
}
}
/**
* RMI服务器,处理每一个连接客户端的请求
* @Author :漠殇
* @Data :Create in 11:24 2021/7/16
*/
public class RmiServer implements Runnable, ISpeaker {
private ServerSocket serverSocket;
private int serverPort;
private volatile boolean goon;
private List<IListener> listeners;
public RmiServer() {
this.listeners = new ArrayList<>();
this.goon = false;
}
public int getServerPort() {
return serverPort;
}
public void setServerPort(int serverPort) {
this.serverPort = serverPort;
}
public boolean isStartUp() {
return this.goon == true;
}
public boolean isShutDown() {
return this.goon == false;
}
public void startUp() throws IOException {
if (this.goon == true) {
speakOut("RmiServer started");
}
this.goon = true;
this.serverSocket = new ServerSocket(this.serverPort);
new Thread(this).start();
speakOut("RmiServer start");
}
public void shutDown() {
if (this.goon == false) {
speakOut("RmiServer not start");
}
close();
}
@Override
public void run() {
while (this.goon) {
try {
Socket client = serverSocket.accept();
String clientIp = client.getInetAddress().getHostAddress();
speakOut("用户[" + clientIp + "]上线");
//TODO 单独处理每个客户请求
new RmiServerCommunication(client);
} catch (IOException e) {
e.printStackTrace();
}
}
close();
}
void close() {
this.goon = false;
if (this.serverSocket!= null && !this.serverSocket.isClosed()) {
try {
this.serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
this.serverSocket = null;
}
}
}
@Override
public void addListener(IListener listener) {
this.listeners.add(listener);
}
@Override
public void removeListener(IListener listener) {
this.listeners.remove(listener);
}
@Override
public void speakOut(String message) {
System.out.println(message);
}
}
/**
* 真正完成方法的调用和执行的类
* 客户端将参数和方法名传输过来,这里真正执行,并返回执行结果
* @Author :漠殇
* @Data :Create in 12:04 2021/7/16
*/
public class RmiServerCommunication implements Runnable{
private Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
public RmiServerCommunication(Socket socket) throws IOException {
this.socket = socket;
this.dis = new DataInputStream(this.socket.getInputStream());
this.dos = new DataOutputStream(this.socket.getOutputStream());
new Thread(this, "RMI-SERVER-COMMUNICATION").start();
}
@Override
public void run() {
try {
String methodId = this.dis.readUTF();
String strParameter = this.dis.readUTF();
RmiInterfaceDefinition rid = RmiInterfaceFactory.getMethod(methodId);
if (rid == null) {
new Exception("[ " + methodId + " ]不存在");
}
Object object = rid.getObject();
Method method = rid.getMethod();
Object[] objects = getParameterValues(method, strParameter);
Object res = method.invoke(object, objects);
//只有存在返回值,才执行下面的语句
if (!method.getReturnType().equals(void.class)) {
this.dos.writeUTF(ArgumentMaker.gson.toJson(res));
}
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
close();
}
}
/**
* 根据对端传输过来的parameter字符串,解析出真正的的参数数组
* @param method
* @param strParameter
* @return
*/
private Object[] getParameterValues(Method method, String strParameter) {
ArgumentMaker argumentMaker = new ArgumentMaker(strParameter);
int parameterCounts = method.getParameterCount();
if (parameterCounts <= 0) {
return new Object[]{};
}
Parameter[] parameters = method.getParameters();
Object[] values = new Object[parameterCounts];
for (int i = 0; i < parameterCounts; i++) {
String key = "arg" + i;
values[i] = argumentMaker.getParameter(key, parameters[i].getParameterizedType());
}
return values;
}
private void close() {
try {
if (this.dis != null) {
this.dis.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
this.dis = null;
}
try {
if (this.dos != null) {
this.dos.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
this.dos = null;
}
try {
if (this.socket != null) {
this.socket.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
this.socket = null;
}
}
}
/**
* 代理使用的入口,通过调用getProxy()方法,完成代理的使用
* @Author :漠殇
* @Data :Create in 9:24 2021/7/16
*/
public class JDkProxy {
private RmiClient rmiClient;
public JDkProxy() {
}
public void setRmiClient(RmiClient rmiClient) {
this.rmiClient = rmiClient;
}
public <T> T getProxy(Class<?> interfaze) {
if(!interfaze.isInterface()) {
return null;
}
ClassLoader classLoader = interfaze.getClassLoader();
Class<T>[] classes = new Class[] {interfaze};
return (T) Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这里启动rmi客户端连接程序,真正发送请求
RmiClientCommunication communication = new RmiClientCommunication(rmiClient.getNodeAddress());
communication.setMethod(method);
communication.setArgs(args);
Object res = communication.doRmiAccept();
return res;
}
});
}
}
/**
* 用户层面使用,需要将服务器地址和端口号通过构造方法进行设定,通过set方法,可以使用不同的RMI服务器
* @Author :漠殇
* @Data :Create in 11:52 2021/7/16
*/
public class RmiClient {
private NodeAddress nodeAddress; //旧地址
private String ip;
private int port;
public RmiClient(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void setNodeAddress(NodeAddress nodeAddress) {
this.nodeAddress = nodeAddress;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public NodeAddress getNodeAddress() {
return new NodeAddress(this.ip, this.port);
}
}
/**
* 客户端真正处理方法调用的类
* 通过set方法,拥有需要执行的接口方法和参数,再将真正的参数传递到RMI服务器,等待RMI服务器的回传信息,将结果再返回给调用端
* 注意:返回值若为void,则不需要等待回传信息
* @Author :漠殇
* @Data :Create in 15:02 2021/7/16
*/
public class RmiClientCommunication {
private NodeAddress nodeAddress;
private Method method;
private Object[] args;
private Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
public void setNodeAddress(NodeAddress nodeAddress) {
this.nodeAddress = nodeAddress;
}
public void setMethod(Method method) {
this.method = method;
}
public void setArgs(Object[] args) {
this.args = args;
}
RmiClientCommunication(NodeAddress nodeAddress) {
this.nodeAddress = nodeAddress;
}
Object doRmiAccept() {
try {
this.socket = new Socket(nodeAddress.getIp(), nodeAddress.getPort());
this.dis = new DataInputStream(this.socket.getInputStream());
this.dos = new DataOutputStream(this.socket.getOutputStream());
this.dos.writeUTF(String.valueOf(this.method.toString().hashCode()));
this.dos.writeUTF(argToString(this.args));
//只有存在返回值,才执行下面的语句
if (!method.getReturnType().equals(void.class)) {
String resStr = this.dis.readUTF();
Object result = ArgumentMaker.gson.fromJson(resStr, this.method.getGenericReturnType());
return result;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String argToString(Object[] args) {
ArgumentMaker argumentMaker = new ArgumentMaker();
if (args == null) {
return null;
}
for (int i = 0; i < args.length; i++) {
argumentMaker.add("arg" + i, args[i]);
}
return argumentMaker.toString();
}
}