内容简介:类加载器之间的这种层次关系叫做双亲委派模型。双亲委派模型要求除了顶层的启动类加载器(Bootstrap ClassLoader)外,其余的类加载器都应当有自己的父类加载器。这里的类加载器之间的父子关系一般不是以继承关系实现的,而是用组合实现的。从源码中我们看到
- 启动类加载器 BootStrap ClassLoader :最顶层的类加载器,负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。可以通
System.getProperty("sun.boot.class.path")查看加载的路径。 - 扩展类加载器 Extention ClassLoader :主要加载目录
%JRE_HOME%\lib\ext目录下的jar包和class文件,或通过java.ext.dirs系统变量指定路径中的类库。也可以通过System.out.println(System.getProperty("java.ext.dirs"))查看加载类文件的路径。 - 应用程序类加载器 Application ClassLoader :也叫做系统类加载器,可以通过
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);
}
复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- springMVC容器加载源码分析
- caffe源码阅读(1): 数据加载
- Glide 图片加载框架源码解析
- Tinker源码分析(二):加载补丁
- 【MyBatis源码分析】Configuration加载(下篇)
- 【MyBatis源码分析】Configuration加载(上篇)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Usability for the Web
Tom Brinck、Darren Gergle、Scott D. Wood / Morgan Kaufmann / 2001-10-15 / USD 65.95
Every stage in the design of a new web site is an opportunity to meet or miss deadlines and budgetary goals. Every stage is an opportunity to boost or undercut the site's usability. Thi......一起来看看 《Usability for the Web》 这本书的介绍吧!