自定义ClassLoader从erlang服务器读class内容

xiaoxiao2022-06-22  60

自定义了个ClassLoader,用socket从一个server上获取class文件内容,然后创建一个类。tcp server是用erlang写的,只负责从硬盘读数据,然后传到自定义ClassLoader。特别注意的是,要想erlang socket跟java socket通信,gen_tcp:listen(Port,[binary,{packet,0}]),这里packet一定要为0,这个是erlang数据包的包头,通信的时候客户端跟服务端加的额外数据,跟java通信,是不能加的,否则会出现error msgsize这类的错误。 -module(class_file_server).-export([start/0,start/1,process_request/1]).-define(PORT,7777).-define(CLASS_NOT_FOUND,"class_not_found_exception").start() -> start(?PORT).start(Port) -> case gen_tcp:listen(Port,[binary,{packet,0},{active,true}]) of {ok,Socket} -> process_request(Socket); {error,Reason} -> io:format("Fail to create socket: ~s ~n",[Reason]) end.process_request(Socket) -> case gen_tcp:accept(Socket) of {ok,From} -> spawn(class_file_server,process_request,[Socket]), receive_data_then_send_file(From); {error,closed} -> io:format("Failed to accept, for {error,closed}~n"); {error,Reason} -> io:format("Failed to accept: ~s~n",[Reason]); Other -> io:format("accept Other ~p~n",[Other]) end.receive_data_then_send_file(FromSocket) -> receive {tcp,FromSocket,Bin} -> io:format("receive some raw data: ~p ~n from ~p~n",[Bin,inet:peername(FromSocket)]), send_file(FromSocket,binary_to_list(Bin)), gen_tcp:close(FromSocket); {tcp_closed,FromSocket} -> io:format("processed one request:~p~n",[FromSocket]), gen_tcp:close(FromSocket); Other -> io:format("Invalid data: ~p~n",[Other]) end.send_file(FromSocket,FileName) -> case file:read_file(FileName) of {ok,Bin} -> gen_tcp:send(FromSocket,Bin); {error,Why} -> gen_tcp:send(FromSocket,?CLASS_NOT_FOUND), io:format("Failed to load class: ~p ~n because ~p~n",[FileName,Why]) end. package classloader;public class RemoteClassLoader extends ClassLoader { protected Class<?> findClass(String name) throws ClassNotFoundException { DownloadManager manager = new DownloadManager(7777); try { byte[] data = manager.download(name); return defineClass(name, data, 0, data.length); } catch (ClassNotFoundException e) { return super.findClass(name); } } @SuppressWarnings("unchecked") public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ RemoteClassLoader loader = new RemoteClassLoader(); Thread.currentThread().setContextClassLoader(loader);// Class clazz = loader.loadClass("com.kingdee.eas.LoadedClazz"); Class clazz = Class.forName("com.kingdee.eas.LoadedClazz",true,loader); clazz.newInstance(); // clazz.newInstance(); }} package classloader;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.net.UnknownHostException;import java.util.Arrays;public class DownloadManager { private static final String CLASS_NOT_FOUND = "class_not_found_exception"; private static final byte[] BYTES_CLASS_NOT_FOUND = CLASS_NOT_FOUND.getBytes(); private static final int SIZE = 204800; private int port; private byte[] result = new byte[SIZE * 10]; private byte[] buffer = new byte[SIZE]; public DownloadManager(int port) { super(); this.port = port; } public byte[] download(String name) throws ClassNotFoundException { // E:\\develop\\workspaces\\workspace-java\\jdbcdriver\\test\\com\\kingdee\eas\LoadedClazz.java String classFile = "E:\\develop\\workspaces\\workspace-java\\jdbcdriver\\bin\\" + name.replaceAll("\\.", "/") + ".class"; Socket socket = null; OutputStream out = null; InputStream in = null; int count = 0, totalCount = 0; try { socket = new Socket("192.168.18.27", this.port); // write to socket out = new BufferedOutputStream(socket.getOutputStream()); out.write(classFile.getBytes()); out.flush(); // read from socket in = new BufferedInputStream(socket.getInputStream()); while ((count = in.read(buffer)) > 0) { if (isEqual(BYTES_CLASS_NOT_FOUND, buffer, count)) { throw new ClassNotFoundException(classFile); } System.arraycopy(buffer, 0, result, totalCount, count); totalCount += count; } for (int i = 0; i < totalCount; i++) { System.out.print(String.format("X", result[i])); if ((i + 1) % 100 == 0) System.out.println(); } System.out.println(); return Arrays.copyOfRange(result, 0, totalCount); } catch (UnknownHostException e) { throw new ClassNotFoundException(classFile); } catch (IOException e) { throw new ClassNotFoundException(classFile); } finally { try { if (out != null) out.close(); if (in != null) in.close(); if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } private static boolean isEqual(byte[] dest, byte[] buffer, int size) { if (dest.length != size) return false; for (int i = 0; i < size; i++) { if (dest[i] != buffer[i]) return false; } return true; } /** * @param args * @throws IOException * @throws UnknownHostException * @throws ClassNotFoundException */ public static void main(String[] args) throws UnknownHostException, IOException, ClassNotFoundException { DownloadManager manager = new DownloadManager(7777); manager.download(""); }} 这里写死了类路径的,你也可自己写自己的。另外需要指明的是,自定义的类装载的的双亲装载器是在ClassLoader类的默认构造函数里设置的,通过getSystemClassLoader()得到的AppClassLoader。而自定义的ClassLoader只实现findClass方法,可以保留loadClass方法原先的双亲委派模型,不用自己去加载所有的类。
转载请注明原文地址: https://www.6miu.com/read-4951172.html

最新回复(0)