(旧文整理)彻底搞懂Java ClassLoader(三)
这篇文章接着上一篇文章,继续完善SimpleClassLoader。在上一篇SimpleClassLoader1的基础上,这次继续补全代码,叫做SimpleClassLoader2。
有了dirs,接下来的工作是在这些目录中查找所需要加载的类,我们要实现ClassLoader的findClass()方法,而findClass()方法需要defineClass()来将class文件读入JVM,加载成class。ClassLoader的defineClass()方法定义如下:
protected final Class defineClass(String name,
byte[] b,
int off,
int len)
throws ClassFormatError
其中name为类名,byte[]数组b,则是读入的.class类文件的数据内容。因此,我们可以定义一个getClassData()方法,将.class文件的内容读进byte[]数组:
protected byte[] getClassData(String directory, String name)
然后在findClass()中使用它:
public synchronized Class findClass(String name)
throws ClassNotFoundException {
for (String dir : dirs) {
byte[] buf = getClassData(dir, name);
if (buf != null)
return defineClass(name, buf, 0, buf.length);
}
throw new ClassNotFoundException();
}
注意ClassLoader对findClass()的定义包含synchronized关键字,保证在多线程环境下,多个线程不会在读入同一个Class,以免造成互锁的情况。
以下是完整的SimpleClassLoader的代码,我们命名为SimpleClassLoader2:
package io.alchemystudio.classloader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class SimpleClassLoader2 extends SimpleClassLoader1 {
public SimpleClassLoader2(String path) {
super(path);
}
public synchronized Class findClass(String name)
throws ClassNotFoundException {
for (String dir : dirs) {
byte[] buf = getClassData(dir, name);
if (buf != null)
return defineClass(name, buf, 0, buf.length);
}
throw new ClassNotFoundException();
}
protected byte[] getClassData(String directory, String name) {
String[] tokens = name.split("\\.");
String classFile = directory + "/" + tokens[tokens.length - 1]
+ ".class";
File f = (new File(classFile));
int classSize = (Long.valueOf(f.length())).intValue();
byte[] buf = new byte[classSize];
try {
FileInputStream filein = new FileInputStream(classFile);
filein.read(buf);
filein.close();
} catch (IOException e) {
return null;
}
return buf;
}
}
以上是完整的实现。我们可以看一下完成后的两个classes的类图:

然后看一下findClass()方法的逻辑图:

可以看到核心就是这个defineClass(),它会在runtime来加载这个class。
本文就先讲到这里,下一篇文章里,我们来实际使用这个SimpleClassLoader2来进行class的加载。
这篇文章用到的代码在这里:
有兴趣可以下载看看。