(旧文整理)彻底搞懂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的加载。
这篇文章用到的代码在这里:
有兴趣可以下载看看。