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

自定义了个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("%02X", 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方法原先的双亲委派模型,不用自己去加载所有的类。

你可能感兴趣的:(java,thread,.net,socket,erlang)