System.getProperty("sun.boot.class.path") 查看加载的路径。 %JRE_HOME%/lib/ext 目录下的 jar 包和 class 文件,或通过java.ext.dirs系统变量指定路径中的类库。也可以通过 System.out.println(System.getProperty("java.ext.dirs")) 查看加载类文件的路径。 getSystemClassLoader() 获取,负责加载用户路径 classpath 上的类库。如果没有自定义类加载器,一般这个就是默认的类加载器。
类加载器之间的这种层次关系叫做双亲委派模型。
双亲委派模型要求除了顶层的启动类加载器(Bootstrap ClassLoader)外,其余的类加载器都应当有自己的父类加载器。这里的类加载器之间的父子关系一般不是以继承关系实现的,而是用组合实现的。
public class Launcher {
private static Launcher launcher = new Launcher();
private static String bootClassPath =
System.getProperty("sun.boot.class.path");
public static Launcher getLauncher() {
return launcher;
}
private ClassLoader loader;
public Launcher() {
// Create the extension class loader
ClassLoader extcl;
try {
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
"Could not create extension class loader", e);
}
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader", e);
}
Thread.currentThread().setContextClassLoader(loader);
}
/*
* Returns the class loader used to launch the main application.
*/
public ClassLoader getClassLoader() {
return loader;
}
/*
* The class loader used for loading installed extensions.
*/
static class ExtClassLoader extends URLClassLoader {}
/**
* The class loader used for loading from java.class.path.
* runs in a restricted security context.
*/
static class AppClassLoader extends URLClassLoader {}
复制代码
从源码中我们看到
(1) Launcher 初始化的时候创建了 ExtClassLoader 以及 AppClassLoader ,并将 ExtClassLoader 实例传入到 AppClassLoader 中。
(2)虽然上一段源码中没见到创建 BoopStrap ClassLoader ,但是程序一开始就执行了 System.getProperty("sun.boot.class.path") 。
附上 Launcher 相关文章: blog.csdn.net/jyxmust/art…
AppClassLoader 的父加载器为 ExtClassLoader , ExtClassLoader 的父加载器为 null , BoopStrap ClassLoader 为顶级加载器。 当JVM加载 Test.class 类的时候
AppClassLoader )是否已经加载过 Test.class 。 ExtClassLoader )是否已经加载过。 BoopStrap ClassLoader )是否已经加载过。 BoopStrap ClassLoader 没有加载过,则到自己指定类加载路径 sun.boot.class.path 下查看是否有 Test.class 字节码,有则加载并返回加载后的类 c = findBootstrapClassOrNull(name) 。 c = findClass(name) 到加载器 ExtClassLoader 指定的类加载路径 java.ext.dirs 下查找 class 文件,有则加载并返回类。 Test.class 字节码,则抛出异常 ClassNotFoundException 。 这里注意
每个自定义的类加载器都需要重写 findClass 方法,该方法的作用是到指定位置查找 class 文件并加载到JVM中,如果找不到则抛出 ClassNotFoundException 异常。
双亲委派模型最大的好处就是让Java类同其类加载器一起具备了一种带优先级的层次关系。这句话可能不好理解,我们举个例子。比如我们要加载顶层的Java类—— java.lang.Object 类,无论我们用哪个类加载器去加载 Object 类,这个加载请求最终都会委托给 Bootstrap ClassLoader ,这样就保证了所有加载器加载的 Object 类都是同一个类。
双亲委派模型的实现比较简单,在 java.lang.ClassLoader 的 loadClass 方法中:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
复制代码
/**
* Finds the class with the specified <a href="#name">binary name</a>.
* This method should be overridden by class loader implementations that
* follow the delegation model for loading classes, and will be invoked by
* the {@link #loadClass <tt>loadClass</tt>} method after checking the
* parent class loader for the requested class. The default implementation
* throws a <tt>ClassNotFoundException</tt>.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class could not be found
*
* @since 1.2
*/
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
复制代码
参考链接:
www.jianshu.com/p/5f79217f2… nomico271.github.io/2017/07/07/… www.cnblogs.com/gdpuzxs/p/7…