一、java加载器介绍
java中有三类预定义加载器分别是
AppClassLoader、ExtClassLoader、BootstrapClassLoader,其中,前2个加载器是java实现的通过继承
URLClassLoader实现,在
sun.misc.Launcher
[/color]类中可以看到源码,而BootstrapClassLoader[color=blue]为本地代码实现,java采用的是父委托机制来加载类。
二、父委托机制介绍
假设系统加载器
AppClassLoader需要加载类A,那么,系统加载器会先委托其父加载器去加载,同样父加载器也会委托给其父加载器,一层一层往上委托直到父加载器为null,这时会调用
BootstrapClassLoader去加载,如果加载失败,则从上往下一个个加载器去加载,如果到
AppClassLoader加载时还未加载成功,则抛出
ClassNotFoundException。
具体的加载过程可以看
ClassLoader类的
loadClass方法:、
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 首先判断该类型是否已经被加载
Class c = findLoadedClass(name);
if (c == null) {
//如果没有被加载,就委托给父类加载或者委派给启动类加载器加载
try {
if (parent != null) {
//如果存在父类加载器,就委派给父类加载器加载
c = parent.loadClass(name, false);
} else {
//如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
三、三类加载器的加载路径分析
通过下面的代码打印出加载器的加载路径:
import java.net.URL;
import java.net.URLClassLoader;
public class AnalyzeClassLoaderPath {
public static void main(String[] args) {
System.out.println("BootstrapClassLoader 的加载路径:");
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL url : urls) {
System.out.println(url);
}
System.out.println("--------------------------------------");
URLClassLoader extClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader().getParent();
System.out.println(extClassLoader);
System.out.println("扩展类加载器 的加载路径:");
urls = extClassLoader.getURLs();
for (URL url : urls) {
System.out.println(url);
}
System.out.println("--------------------------------------");
// 获取appclassloader
URLClassLoader appClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
System.out.println(appClassLoader);
System.out.println("App类加载器 的加载路径:");
urls = appClassLoader.getURLs();
for (URL url : urls) {
System.out.println(url);
}
System.out.println("--------------------------------------");
}
}
输出结果如下:
BootstrapClassLoader 的加载路径:
file:/E:/jdk1.6.0_06/jre/lib/resources.jar
file:/E:/jdk1.6.0_06/jre/lib/rt.jar
file:/E:/jdk1.6.0_06/jre/lib/sunrsasign.jar
file:/E:/jdk1.6.0_06/jre/lib/jsse.jar
file:/E:/jdk1.6.0_06/jre/lib/jce.jar
file:/E:/jdk1.6.0_06/jre/lib/charsets.jar
file:/E:/jdk1.6.0_06/jre/classes
--------------------------------------
sun.misc.Launcher$ExtClassLoader@6b97fd
扩展类加载器 的加载路径:
file:/E:/jdk1.6.0_06/jre/lib/ext/dnsns.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/localedata.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/sunjce_provider.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/sunmscapi.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/sunpkcs11.jar
--------------------------------------
sun.misc.Launcher$AppClassLoader@192d342
App类加载器 的加载路径:
file:/E:/workspace/dreams/target/classes/
--------------------------------------
我们也可以将自己写的java类放到上面的路径中,交由不同的加载器进行加载,
经过试验发现在jre/classes下放入class文件可以加载,但在jre/lib目录下的jar包中加入class文件或加入jar包都不能加载,而在jre/lib/ext目录下加入jar包可以加载但class文件不行。