2012-03-14 65 views
2

我有两个类如下如何以及当Bootstrap jar找到../ lib/rt.jar和../lib/ext.**jar时被加载?

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? >>[email protected] 

我的问题是如下:

  1. 为什么那些java.lang.Systemjava.nio.charset.Charset等如前所述ve会被加载CustomClassLoader?在我的想法中,当我运行java -Djava.system.class.loader foo.Test时,JVM首先搜索类foo.Test,加载它,执行主要方法,然后当它检测到System.out.println()时,它将继续加载类java.lang.Systemjava.io.PrintWriter,因为这些类是由它使用的, ?

  2. 当我运行它使用位于java.lang包中的一些类的类,这些类也将被再次加载,在我的情况下放CustomClassLoader >> >>的ExtClassLoader BoostrapClassLoader加载?

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

非常感谢您的帮助!

回答

3

要回答你的问题,让我们依次进行。

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

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

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

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

2

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

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

  2. 在你的情况下,CustomClassLoader将非foo类的加载委托给super,它不会再次加载同一个类,但返回以前加载的类。

  3. 谈论加载罐子误导。来自这些罐子的类别按需加载。为了加载任何程序,JVM需要创建一个线程,所以Thread类和它的依赖关系在你的类之前加载。

您可以使用-verbose:class运行sun的java来查看类是如何加载的。

相关问题