`

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

    博客分类:
  • java
阅读更多
自定义了个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方法原先的双亲委派模型,不用自己去加载所有的类。
分享到:
评论

相关推荐

    自定义classloader的使用

    创建自定义Classloader需要继承java.lang.ClassLoader类,并重写其关键方法,如`findClass(String name)`或`loadClass(String name)`。这两个方法分别用于查找指定类的字节码和实际加载类。在`findClass`中,我们...

    Java实现热加载完整代码;Java动态加载class;Java覆盖已加载的class;Java自定义classloader

    让Java支持热加载是个不错的想法。如何做到的呢? 1. 定义好接口和实现类 2. 让代理类通过反射的方式调用实现类,对外暴露的是代理类。 3. 自定义URLClassLoader。检查实现类.class文件的...Java自定义classloader;

    定义ClassLoader调用外部jar包

    当我们需要从外部jar包动态加载类时,自定义ClassLoader就显得尤为关键。这篇博文"定义ClassLoader调用外部jar包"探讨了如何创建一个自定义的ClassLoader,以便能够灵活地加载不在应用主类路径(ClassPath)中的jar...

    ClassLoader运行机制 自己写的

    这里我们将详细讨论ClassLoader的运行机制,特别是自定义ClassLoader的设计与实现。 ClassLoader的基本职责是根据类名动态加载对应的类文件。在Java中,类加载过程遵循双亲委派模型(Parent Delegation Model)。这...

    使用classloader动态加载Class

    自定义ClassLoader需要重写`findClass()`或`loadClass()`方法。`loadClass()`方法是类加载的入口,它会调用`findClass()`来查找指定类的字节码。一旦找到,使用`defineClass()`方法将字节码转换为Class对象。 2. **...

    使用自定义ClassLoader解决反序列化serialVesionUID不一致问题 _ 回忆飘如雪1

    - **方便添加Class和JAR**:自定义`ClassLoader`应该提供更灵活的方法,能够直接添加类和JAR,以适应不同的场景需求。 自定义`ClassLoader`的设计和实现是一个高级话题,需要深入理解Java的类加载机制。通过这种...

    java自定义类加载classloader文档,包括代码

    ### Java自定义类加载器(Class Loader)详解 #### 一、引言 在Java语言中,类加载机制是其动态特性的核心之一。通过类加载器(Class Loader),Java程序能够在运行时根据需要加载所需的类,从而实现高度的灵活性...

    classloader

    创建自定义类加载器需要继承ClassLoader类,并重写findClass()方法。在这个方法里,你可以编写代码来从指定的位置(例如,网络、文件系统或内存)读取类的字节码,并通过defineClass()方法将其转换为Class对象。 在...

    ClassLoader 案例

    用户可以输入类名或指定目录,然后自定义ClassLoader将从这些位置加载更新的类。这里可能需要使用到文件I/O操作,以及对.class文件格式的理解。 Java反射是另一个关键概念,它允许程序在运行时检查和修改自身的行为...

    classloader 加密解密应用程序 ,反编译class

    在程序运行时,通过自定义的`ClassLoader`,在加载类之前先解密这些加密的字节码,然后再交给JVM执行。这样可以增加逆向工程的难度,防止代码被恶意分析或篡改。加密解密的过程通常涉及到对字节码的操作,例如使用...

    关于Classloader的总结!loadClass的分析和加载细节的分析

    在Java编程语言中,`Classloader`(类加载器)是一个至关重要的组件,它负责将类的`.class`文件从磁盘加载到JVM(Java虚拟机)内存中,使得程序能够执行。这篇博文主要围绕`Classloader`的`loadClass`方法进行深入...

    ClassLoader小例子

    - 自定义ClassLoader通常需要重写`loadClass()`方法,该方法在找不到类时调用`findClass()`进行实际的加载操作。 - 在`ClassLoaderDemo`这个例子中,可能就展示了如何创建一个自定义的ClassLoader,从非标准位置...

    关于Android中自定义ClassLoader耗时问题的追查

    在Android开发中,自定义ClassLoader是一项关键技能,尤其在实现热修复和插件化技术时。本文主要探讨了Android中自定义ClassLoader导致的性能问题,特别是冷启动速度的影响。问题的核心在于,通过插入自定义的...

    Java ClassLoader定制实例

    在某些特定场景下,比如动态加载代码、插件系统或者安全隔离等,我们需要自定义ClassLoader来实现特定的加载逻辑。例如,我们可能希望加载网络上的类,或者从数据库中读取类的字节码。 以...

    MyCLRepl:自定义 Scala REPL 示例以添加自定义 ClassLoader 和自定义 REPL 命令

    自定义 ClassLoader 加载任何类时的类名。 ":myCommand" 命令位于默认 REPL 命令之上。 scala &gt; val hello = " hello " MyClassLoader loads classOf &lt; root&gt;.$line3 &lt;&lt;中略&gt;&gt; MyClassLoader loads classOf ...

    ClassLoader类加载器

    在上述代码中,`loadClassData`方法需要根据实际的需求去实现,例如读取指定路径的.class文件内容,或者从网络上下载字节码数据。 在实际开发中,自定义ClassLoader可能涉及到安全问题,因此必须谨慎处理。例如,...

    Understanding the Java ClassLoader

    - **编译源代码**:在加载前,自定义ClassLoader会读取源代码并编译成.class文件。 - **加载编译后的类**:编译完成后,ClassLoader将加载编译后的字节码文件到JVM中。 **2. 实现细节** - **源代码读取**:使用...

    ClassLoader 详解.doc

    自定义ClassLoader通常需要重写findClass()或loadClass()方法,以控制类的加载行为。 理解ClassLoader的工作原理对于排查类冲突、处理依赖关系以及优化大型J2EE应用的性能具有重要意义。开发者可以通过日志输出、...

    理解Java ClassLoader机制

    自定义ClassLoader需要继承`java.lang.ClassLoader`类,并重写`findClass()`或`loadClass()`方法。通过这两个方法,你可以控制类的加载来源和方式。 在实际开发中,理解ClassLoader机制可以帮助解决一些问题,例如...

Global site tag (gtag.js) - Google Analytics