(旧文整理)彻底搞懂Java ClassLoader(三)

这篇文章接着上一篇文章,继续完善SimpleClassLoader。在上一篇SimpleClassLoader1的基础上,这次继续补全代码,叫做SimpleClassLoader2

有了dirs,接下来的工作是在这些目录中查找所需要加载的类,我们要实现ClassLoaderfindClass()方法,而findClass()方法需要defineClass()来将class文件读入JVM,加载成class。ClassLoaderdefineClass()方法定义如下:

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();  
}  

注意ClassLoaderfindClass()的定义包含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的加载。

这篇文章用到的代码在这里:

有兴趣可以下载看看。

My Github Page: https://github.com/liweinan

Powered by Jekyll and Theme by solid

If you have any question want to ask or find bugs regarding with my blog posts, please report it here:
https://github.com/liweinan/liweinan.github.io/issues