自定义了个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的使用。 一、Classloader的工作原理 Java的类加载机制遵循双亲...
这篇博文"定义ClassLoader调用外部jar包"探讨了如何创建一个自定义的ClassLoader,以便能够灵活地加载不在应用主类路径(ClassPath)中的jar包中的类。 首先,我们需要理解ClassLoader的工作原理。默认情况下,Java...
让Java支持热加载是个不错的想法。如何做到的呢? 1. 定义好接口和实现类 2. 让代理类通过反射的方式调用实现类,对外暴露的是代理类。 3. 自定义URLClassLoader。检查实现类.class文件的...Java自定义classloader;
标题和描述中提到的解决方案是通过自定义`ClassLoader`来处理`serialVersionUID`不一致的问题。以下是几种常见方法的优缺点以及自定义`ClassLoader`的详细解释: 1. **修改序列化byte数据**: 这种方法直接修改已...
这里我们将详细讨论ClassLoader的运行机制,特别是自定义ClassLoader的设计与实现。 ClassLoader的基本职责是根据类名动态加载对应的类文件。在Java中,类加载过程遵循双亲委派模型(Parent Delegation Model)。这...
创建自定义类加载器需要继承ClassLoader类,并重写findClass()方法。在这个方法里,你可以编写代码来从指定的位置(例如,网络、文件系统或内存)读取类的字节码,并通过defineClass()方法将其转换为Class对象。 在...
在Android开发中,自定义ClassLoader是一项关键技能,尤其在实现热修复和插件化技术时。本文主要探讨了Android中自定义ClassLoader导致的性能问题,特别是冷启动速度的影响。问题的核心在于,通过插入自定义的...
自定义ClassLoader允许开发者根据特定需求加载类,比如动态加载或更新类文件,这在某些高级应用场景中非常有用,如插件系统、热部署等。本案例将深入探讨如何创建一个自定义的ClassLoader,利用Java反射和注解技术...
上述代码展示了如何创建一个自定义类加载器`MyClassLoader`,该类继承自`java.lang.ClassLoader`。`MyClassLoader`的主要功能是从文件系统中加载指定类的二进制数据。 - **构造函数**:接受一个父类加载器和基础...
下面我们将详细讨论ClassLoader的基本概念、工作流程以及如何自定义ClassLoader。 1. **ClassLoader的基本概念** - 类加载器是Java中的一个核心组件,它负责将类的.class文件加载到JVM中,并转换为可执行的Java...
自定义 ClassLoader 加载任何类时的类名。 ":myCommand" 命令位于默认 REPL 命令之上。 scala > val hello = " hello " MyClassLoader loads classOf < root>.$line3 <<中略>> MyClassLoader loads classOf ...
在某些特定场景下,比如动态加载代码、插件系统或者安全隔离等,我们需要自定义ClassLoader来实现特定的加载逻辑。例如,我们可能希望加载网络上的类,或者从数据库中读取类的字节码。 以...
为了更好地理解和利用Java的这一特性,本篇将详细介绍Java ClassLoader的作用及其工作原理,并通过构建一个示例ClassLoader来帮助读者深入理解如何自定义ClassLoader,从而扩展JVM的功能。 #### 二、ClassLoader...
了解和掌握ClassLoader的工作原理以及如何自定义ClassLoader对于深入理解Java应用程序的运行机制非常有帮助。以下是对ClassLoader API的使用和自定义的详细说明。 首先,我们来看ClassLoader的基本概念。在Java中,...
但有时我们可能需要打破这种模型,比如实现类的版本控制或插件系统,这时可以通过自定义ClassLoader来实现。 5. 类加载器的关系图 Java中的ClassLoader形成了一个树状结构,Bootstrap ClassLoader位于顶端,其他类...
3-7Tomcat中自定义类加载器的使用与源码实现(1).mp4
通过阅读给出的博文链接,我们可以深入理解ClassLoader的功能、分类以及如何进行自定义。 首先,ClassLoader的基本职责是加载.class文件,将字节码转化为运行时的Java对象。这个过程分为三个步骤:加载、验证和初始...
理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先,我们来了解一下ClassLoader的基本层次结构。在Java中,ClassLoader分为三个主要层次:Bootstrap ClassLoader、...
深入理解ClassLoader的工作原理对于优化应用性能、解决类加载问题以及实现自定义加载策略至关重要。 首先,JVM启动时,会构建一个类加载器的层次结构,主要包括三个基本类加载器: 1. Bootstrap ClassLoader:引导...