在java
中,加载一个类到jvm
虚拟机并为其实例化一个对象是由ClassLoader
实现的
有时候,我们需要实现特殊的类加载方式,就需要自己实现一个ClassLoader
ClassLoader
中有几个比较重要的方法:
loadClass
:
该方法实现了双亲委托机制,一般不会重写该方法,他的执行步骤是先委托父加载器加载,如果加载不到,在执行自己的findClass
加载findClass
:
一般实现自己的ClassLoader
都是重写该方法,如果方法找不着,则抛出一个ClassNotFound
异常defineClass
:
该方法是jvm
提供的一个接口,验证一个class
字节码数组,并为其创建一个Class
对象下面简单实现一个
ClassLoader
,用于加载指定目录下的jar
包内的类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60public class JarsClassLoader extends ClassLoader {
private String basePath; //jar包存放的目录
public JarsClassLoader(String path, ClassLoader parentClasss) {
super(parentClasss); //指定父加载器
basePath = path;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classByte = getClassByte(name); //根据类的全路径名去获取一个字节码数组
try {
return defineClass(name, classByte, 0, classByte.length);//生成一个class
} catch (Exception e) {
throw new ClassNotFoundException("找不到类:"+name);
}
}
/**
* 该方法遍历basePath下的jar包,查找是否存在指定的类文件
**/
private byte[] getClassByte(String className) {
try {
File baseDir = new File(basePath);
File[] childrens = baseDir.listFiles();
for (File child : childrens) {
if (!child.getName().endsWith(".jar"))
continue;
//jar包的全路径名
String jarName = basePath + File.separator + child.getName();
//创建一个Zip文件对象
ZipFile zip = new ZipFile(jarName);
//遍历Zip内的所有实体项
Enumeration<ZipEntry> zipEntries = (Enumeration<ZipEntry>) zip.entries();
ZipEntry zn;
while (zipEntries.hasMoreElements()) {
zn = zipEntries.nextElement();
if (!zn.getName().endsWith(".class"))
continue;
//处理实体名,将`/`替换成`.`,并去除`.class`后缀
String znName =
zn.getName().replace("/", ".").replace(".class", "");
//如果找到指定的类文件
if (znName.equals(className)) {
BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(zn));
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) zn.getSize());
byte[] bytes = new byte[1024];
int cnt;
while ((cnt = (bis.read(bytes, 0, bytes.length))) > 0) {
bos.write(bytes, 0, cnt);
}
return bos.toByteArray();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}