自定义ClassLoader
2019-02-19 本文已影响25人
Real_man
ClassLoader在Java中有着非常重要的作用,主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流。它是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责将Class里的二进制数据流装载进系统,然后交给Java虚拟机进行连接,初始化等操作。
在加载阶段,虚拟机需要完成以下三件事:
- 通过类的全限名获取此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转换为方法区的运行时数据区
- 在内存中生成一个代表这个类的Class对象,作为方法区的这个类的各种数据访问入口。
那么如何自定义ClassLoader呢?
其实只需要重写findClass即可,findClass在找到Class对象后,调用defineClass来定义Class字节流。
代码
- 先新建一个Java文件,在系统上的位置,然后用javac编译java文件。
//编译
//javac src/test/java/me/aihe/demo/Hello.java
public class Hello {
static {
System.out.println("hello");
}
}
- 新建ClassLoader,重写findClass方法。
public class MyClassLoader extends ClassLoader {
private String path;
private String classLoaderName;
public MyClassLoader(String path, String classLoaderName) {
this.path = path;
this.classLoaderName = classLoaderName;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private byte[] loadClassData(String name) throws IOException {
name = path + name + ".class";
InputStream is = null;
ByteArrayOutputStream outputStream = null;
try {
is = new FileInputStream(new File(name));
outputStream = new ByteArrayOutputStream();
int i = 0;
while ((i = is.read()) != -1) {
outputStream.write(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.close();
}
if (is != null) {
is.close();
}
}
return outputStream.toByteArray();
}
}
- 新建测试类,看看刚才写的ClassLoader是否生效。
public class ClassLoaderChecker {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MyClassLoader myClassLoader = new MyClassLoader("/Users/aihe/Desktop/extra/spring-boot-learn/src/test/java/me/aihe/demo/", "random");
Class c = myClassLoader.loadClass("Hello");
System.out.println("ClassLoader:" + c.getClassLoader());
Object instance = c.newInstance();
}
}
-
运行查看结果,可以看到尽管Class文件是被我们自己的ClassLoader加载的,并且Class对象可以用来新建Java对象。
image.png
最后
自定义类加载器有很多好处,它让Java代码更加灵活,应用场景:
- 可以用来加密Class文件,然后解密Class文件进行再加载,提高系统安全性
- 从网络中加载Class文件