Bootstrap jar如何以及何时加载?lib / rt.jar和../lib/ext.**jar?

时间:2012-03-14 13:51:18

标签: java classloader

我有两个类列出如下

package foo;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class CustomClassLoader extends ClassLoader {
    public CustomClassLoader(ClassLoader parent){
        super(parent);
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        System.out.println( " >>> loading " + name );

        if (name.startsWith("foo")) {
            return getClass(name);
        }
        return super.loadClass(name);
    }

    public Class getClass(String name){
        try {
            byte[] data= getClassByteData(name);
            return this.defineClass(name, data, 0, data.length);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public byte[] getClassByteData(String name) throws IOException {
        String file = name.replace(".", File.separator)+".class";
        InputStream in   = this.getClass().getResourceAsStream("/"+file);
        int length = in.available();
        byte[] datas = new byte[length];
        in.read(datas, 0, length);
        return datas;
    }
}


package foo;

public class Test {
    public static void main(String[] args) {
        System.out.println(" Who is my loader? >>" + Test.class.getClassLoader());
    }

}

运行:java -Djava.system.class.loader=foo.CustomClassLoader foo.Test

输出:

 >>> loading java.lang.System
 >>> loading java.nio.charset.Charset
 >>> loading java.lang.String
 >>> loading foo.Test
 >>> loading java.lang.Object
 >>> loading java.lang.StringBuilder
 >>> loading java.lang.Class
 >>> loading java.io.PrintStream
 Who is my loader? >>foo.CustomClassLoader@de6ced

我的问题如下:

  1. 为什么java.lang.System会加载上述java.nio.charset.CharsetCustomClassLoader等?在我的想法中,我认为当我运行java -Djava.system.class.loader foo.Test时,JVM首先搜索类foo.Test,加载它,执行main方法,然后当它检测到System.out.println()时,它将继续加载Class java.lang.Systemjava.io.PrintWriter,因为它使用了这些类,对吗?

  2. 当我运行一个使用位于java.lang包中的类的类时,这些类也会再次加载,在我的情况下委托CustomClassLoader&gt;&gt; ExtClassLoader&gt;&gt; BoostrapClassLoader来加载?

  3. 加载/lib/rt.jar/lib/ext/**.jar时,在我们运行像java foo.Test这样的类之前,所有这些类都已经加载了bean?

  4. 提前感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

要回答你的问题,让我们轮流看看。

  1. Java的ClassLoading机制基于委托模型,其中加载类的尝试通常首先委托给父类加载器。如果父类加载器能够成功加载该类,则加载的类将沿委托链向下传递,并返回最初调用的任何类加载器。由于您将自定义类加载器设置为系统类加载器,因此JVM将其实例化为应用程序启动时使用的默认加载器。然后它用于加载它需要的所有类。大多数这些类(即任何不以foo。*开头的类)都被委托给父类加载器,这解释了为什么你看到关于你的类加载器的消息试图加载它们。

  2. 因为非foo。*类的加载被委托给父类加载器,所以加载系统类(如System.out)将再次由父类加载器处理,该加载器处理缓存所有加载的类并将返回先前加载的实例。

  3. 加载rt.jar和lib / ext / * .jar文件由父类加载器(或其父级)处理,而不是您。因此,您的类加载器不需要关注这些JAR文件。

  4. 通常,构建自定义类加载器以确保可以从非标准位置加载类,例如存储在数据库中的JAR。

答案 1 :(得分:2)

我假设你运行的实际命令行是java -Djava.system.class.loader=foo.CustomClassLoader foo.Test

  1. 通常,所有类都可以由不同的类加载器多次加载。事实上,他们甚至被认为是不同的阶级。那么foo.Test需要一个java.lang.System,调用它的类加载器来查找或加载它。

  2. 在您的情况下,CustomClassLoader将非foo类加载委托给super,它不会第二次加载相同的类,但返回先前加载的类。

  3. 谈论装载误导的罐子。这些罐中的类可以按需单独加载。要加载JVM需要创建线程的任何程序,所以甚至在你的类之前加载Thread类及其依赖项。

  4. 你可以使用-verbose:class运行sun的java,看看如何加载类。