java动态类加载常用的类_自定义类加载器和动态加载 Java 代码

有时候,我们需要 java 像脚本一样的运行,甚至是希望我们的代码是热部署,一旦代码文件发生变动就重新加载这个代码,能实现吗?今天就来试着解决下。

d528732ab7dc5acdcc5fedef4c18b4dd.png

自定义类加载器

我们需要一个自定义的类加载器,完成任何路径包括网络的文件加载,这个是取得 java 字节码文件,也就是编译后的 class 文件,他可能在世界的某个角落。

实现自定义的类加载器首先是继承ClassLoader这个类,来看下构造方法代码

public class MyClassLoad extends ClassLoader {

private String rootPath;

public MyClassLoad(String rootPath) {

this.rootPath = rootPath;

}

}

构造方法,仅仅是把路径传入,也就是 class 文件的文件夹,不包括包名称的路径;

接下来重写findClass方法;

/**

* 根据name来寻找该类

*

*/

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

Class> c = findLoadedClass(name);

if (c == null) { // 内存堆中还没加载该类

c = findMyClass(name); // 自己实现加载类

}

return c;

}

首先在内存堆里面查找,没有加载的话就到自己实现,看下findMyClass方法

/**

* 加载该类

*

* @param name

* @return

*/

private Class> findMyClass(String name) {

try {

byte[] bytes = getData(name);

return this.defineClass(null, bytes, 0, bytes.length); // 调用父类方法,生成具体类

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

该方法根据字节数组返回Class类,根据 class 文件获取字节数组可以使用Apache 文件操作相关辅助类,这里使用原生 jdk 实现;

private byte[] getData(String className) {

String path = rootPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class";

InputStream is = null;

try {

is = new FileInputStream(path);

ByteArrayOutputStream stream = new ByteArrayOutputStream();

byte[] buffer = new byte[2048];

int num = 0;

while ((num = is.read(buffer)) != -1) {

stream.write(buffer, 0, num);

}

return stream.toByteArray();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (is != null) {

try {

is.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

return null;

}

这个简单的自定义类加载器就差不多了,如果需要实现自己加密解密的可以在字节数组里面进行折腾,这里不再深入,我们的目标是热加载一段 java代码,可能的解决方法是,构建一个 java 模板,里面内置一些方法,外界可以增加一些新的方法,也可以调用内置方法。

好!开始一个简单的,把一段代码加载到内存并且执行吧。

import java.io.File;

import java.io.FileWriter;

import javax.tools.JavaCompiler;

import javax.tools.JavaCompiler.CompilationTask;

import classload.MyClassLoad;

import javax.tools.JavaFileObject;

import javax.tools.StandardJavaFileManager;

import javax.tools.ToolProvider;

public class LoadJava {

public static final String javaCode = "package classload;public class HelloWorld2 {public HelloWorld2() {System.out.println(\"Hello World\");}}";

public static void runJavaCode() throws Exception {

// 把 java String 存储到文件

String fileName = "/Users/XXXXXXX/Documents/demo/java/classload/HelloWorld2.java";

File file = new File(fileName);

FileWriter fw = new FileWriter(file);

fw.write(javaCode);

fw.flush();

fw.close();

//

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();

StandardJavaFileManager standardFileManager = javaCompiler.getStandardFileManager(null, null, null);

Iterable extends JavaFileObject> iterable = standardFileManager.getJavaFileObjects(fileName);

// 执行编译任务

CompilationTask task = javaCompiler.getTask(null, standardFileManager, null, null, null, iterable);

task.call();

standardFileManager.close();

// 把编译后的 class 文件加载到内存

ClassLoader pcl = new MyClassLoad("/Users/XXXXXXX/Documents/demo/java/");

Class c = pcl.loadClass("classload.HelloWorld2");

System.out.println(c.newInstance());

}

public static void main(String[] args) {

try {

LoadJava.runJavaCode();

} catch (Exception e) {

e.printStackTrace();

}

}

}

代码注释的很清楚了,勿再多言。

版权印为您的作品印上版权32805660

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值