JavaDemo——自定义类加载器加载class文件

本文介绍如何通过继承ClassLoader并重写findClass方法来自定义Java类加载器,实现对特定路径下class文件的加载及使用反射调用其方法。

先准备一个正确的class文件:

先在E:\Temp\javatest目录写了一个简单的java文件并生成一个合法的class文件:

javaDemo:

/**
 * 2021年4月1日下午5:06:10
 */
package testClsLoader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * @author XWF
 *
 */
public class TestClsLoader {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			MyClsLoader mcl = new MyClsLoader("E:\\Temp\\javatest");
			Class<?> cls = mcl.loadClass("Add");
			Object obj = cls.getDeclaredConstructor(null).newInstance(null);
			Method m = cls.getDeclaredMethod("add", int.class, int.class);
			m.invoke(obj, 1, 2);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

class MyClsLoader extends ClassLoader {
	private String path;
	public MyClsLoader(String classFilePath) {
		this.path = classFilePath;
	}
	
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		try {
			byte[] bytes = null;
			try(FileInputStream fis = new FileInputStream(new File(this.path, name + ".class"))) {
				bytes = fis.readAllBytes();
			}
			return defineClass(name, bytes, 0, bytes.length);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return super.findClass(name);
	}
}

执行结果:

继承ClassLoader重写findClass方法,将.class文件读取放到byte数组,传递给defineClass方法生成Class对象,然后使用反射调用方法即可;

一个classLoader对同一个类只能加载一次,若要动态加载,只需新new一个类加载器重新加载即可,旧实例等gc回收,要注意防止存在引用造成内存泄漏;

### 如何在Java中重新加载对象类 在Java中,要实现对象类的重新加载,通常需要自定义`ClassLoader`并处理类的加载和链接过程。以下是关于如何实现这一功能的具体说明: #### 1. 使用自定义 `ClassLoader` 由于Java内置的类加载器会在加载一个类之前检查该类是否已被加载,因此如果希望重新加载某个类,则必须创建自己的`ClassLoader`子类[^2]。 ```java public class CustomClassLoader extends ClassLoader { public CustomClassLoader(ClassLoader parent) { super(parent); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = loadClassData(name); // 加载字节码数据的方法 if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] loadClassData(String className) { // 实现读取.class文件并返回其字节数组逻辑 String path = className.replace('.', '/') + ".class"; try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int data; while ((data = inputStream.read()) != -1) { byteArrayOutputStream.write(data); } return byteArrayOutputStream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } } ``` 上述代码展示了如何通过继承`ClassLoader`来自定义类加载器,并覆盖`findClass()`方法以支持动态加载新的`.class`文件[^3]。 --- #### 2. 处理类的链接问题 每次重新加载类时,都需使用一个新的`CustomClassLoader`实例,因为`resolve()`方法是一个`final`方法且不允许同一个`ClassLoader`多次链接相同的类。 以下是一段演示如何利用新实例化后的`CustomClassLoader`来加载更新版本的类: ```java // 创建第一个类加载器实例 CustomClassLoader loader1 = new CustomClassLoader(Thread.currentThread().getContextClassLoader()); Class<?> clazz1 = loader1.loadClass("com.example.MyReloadableClass"); Object instance1 = clazz1.getDeclaredConstructor().newInstance(); // 修改源代码后重新编译生成新的 .class 文件 // ... // 创建第二个类加载器实例用于加载修改后的类 CustomClassLoader loader2 = new CustomClassLoader(Thread.currentThread().getContextClassLoader()); Class<?> clazz2 = loader2.loadClass("com.example.MyReloadableClass"); Object instance2 = clazz2.getDeclaredConstructor().newInstance(); ``` 注意,在此过程中两个不同版本的对象(`instance1`, `instance2`)属于不同的运行期命名空间,彼此之间无法直接转换或共享静态成员变量[^1]。 --- #### 3. 配置环境以便于动态编译与加载 为了让程序能够实时编译最新的Java文件到内存中的`.class`形式,可以借助JDK自带工具包内的`javax.tools.JavaCompiler`接口完成自动化构建流程[^4]。例如设置如下命令行参数引入必要的库路径: ```bash java -Xbootclasspath/a:/path/to/jdk/lib/tools.jar -jar dynamic-demo.jar ``` 这样做的目的是确保即使应用正在执行期间也能顺利调用内部API来进行增量式的开发调试工作流优化。 --- ### 总结 综上所述,要在Java应用程序里安全有效地实施对象级别的热部署机制并非易事,但只要遵循以上提到的设计原则——即采用独立隔离型定制化的`ClassLoader`结构配合恰当配置好的外部依赖关系链路管理策略即可达成目标。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值