转载自:
http://www.iteye.com/topic/136427
http://blog.youkuaiyun.com/lovingprince/article/details/4238695
http://www.blogjava.net/lhulcn618/archive/2006/05/25/48230.html
Java类加载器
Java中主要有三种类加载器,如下:
bootstrap classloader 引导类加载器,加载 JAVA_HOME/lib目录下的jar包(Java核心API)
|
extension classloader 扩展类加载器,加载JAVA_HOME/lib/ext下的jar包(扩展API)
|
system classloader 应用类加载器,加载classpath下的类
system classloader 的父加载器是 extension classloader
extension classloader 的父加载器是 bootstrap classloader
这里的父子关系不是Java的类继承关系,是一种逻辑上的父子关系( bootstrap classloader是有C++编写的)
我们已经知道Java的类装载器体系结构为树状,
多个类装载器可以指定同一个类装载器作为自己的父类,每个子类装载器就是树状结构的一个分支,
当然它们又可 以个有子类装载器类装载器,类装载器也可以没有父类装载器,这时Bootstrap类装载器将作为 它的隐含父类,实际上Bootstrap类装载器是所有 类装载器的祖先,也是树状结构的根。
Java类的加载使用双亲委派机制:
双亲委派机制即一个类加载器要加载类时,先查看其父加载器是否加载过此类,若加载过,直接返回;若父加载 器也未加载,则父加载器会询问其父加载器,直到询问到根加载器(Bootstrap classLoader)
若父加载器(以及父加载器的父加载器)未加载,则当前加载器自己加载,若自己也无法加载,则抛出异常 ClassNotFoundException NoClassDefFoundError
threadContextClassLoader 指定执行线程中的类由哪个加载器加载
JVM启动时会先使用bootstrap classloader载入并初始化一个Launcher,
Launcher 会根据系统和命令设定初始化好class loader结构,JVM就用它来获得extension classloader和 system classloader,并载入所有的需要载入的Class
//同时Launcher会将system classloader设置成当前线程的context classloader
Thread.currentThread().setContextClassLoader(loader);
因此:
我们在编写Java程序,加载我们创建的类时,一般使用的system classloader(应用类加载器),
除非我们自定义一个classLoader(可通过继承URLClassLoader,通过文件路径查找加载类),
并使用它来加载类
我们在多线程编程中new Thread的时候,线程对象初始化调用init方法时候,
也会设置contextClassLoader的, Thread类init方法摘要如下:
private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
Thread parent = currentThread();
//省略
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
//省略
}
转载自:http://blog.youkuaiyun.com/lovingprince/article/details/4242497
要理类加载体系结构,就必须清楚如下几点比较基本的原则。(下面类加载器 简写为cl(classLoader))
1、cl是一种父子树形结构(注:这里不是指类继承的父子关系)
2、父cl无法看到子cl加载的类
3、虚拟机遵守双亲委托加载原则,即任何子cl必须首先委托父cl先加载需要的类,当父cl加载不到时再由子cl
亲自加载(这是一个递归过程,即父cl如果还有父cl2,那么父cl 又委托给父cl2,依次类推,直到根为止,
如果父cl已经加载过需要的类cl,则子cl直接使用即可)
4、全盘负责:一个classloader加载一个class后,这个class所引用或者依赖的类也由这个classloader载入,
除非显示的用另一个classloader载入
5、类在虚拟机中的标志出来是 : cl实例号+包名+类名,因此不同的cl实例加载相同的类在虚拟机中表现出来
是不同的。这就是为什么多个cl加载同一个类有时候会出现转换 异常的ClassCastException的原因
自定义类加载器:
编写我们自己的类加载器,必须继承ClassLoader,然后覆盖findClass()方法。
ClassLoader超类的loadClass方法用于将类的加载操作委托给父类加载器去进行,只有该类尚未加载并且父类加
载器也无法加载该类时,才调用findClass()方法。
如果要实现该方法,必须做到以下几点:
(1)为来自本地文件系统或者其他来源的类加载其字节码
(2)调用ClassLoader超类的defineClass()方法,向虚拟机提供字节码
转载自:
http://www.cnblogs.com/feiling/archive/2012/08/29/2662909.html
http://sudalyl.iteye.com/blog/1126306
应用 :关于字节码class在网络传递问题,两个系统经过网络传输一个类,一端可以加密class字节码,
然后另 外一端接收后解密,解密后用自定义的加载器加载类(保证了传输的安全性)
可参见:http://www.shangxueba.com/jingyan/91106.html
以下根据两种自定义类加载器实现方式,参照源码的一些理解:
CompileClassLoader extends ClassLoader 参见原文: http://sudalyl.iteye.com/blog/1126306
HotSwapClassLoader extends URLClassLoader (URLClassLoader也继承自ClassLoader)
参见原文: http://www.iteye.com/topic/136427
CompileClassLoader 重写的是findClass方法
HotSwapClassLoader 重写的是loadClass方法
自定义的classLoader都是调用loadClass方法加载类的
系统抽象类public abstract class ClassLoader中的loadClass方法实现方式是:
先委派给双亲加载,若已加载则返回;否则自己加载调用findClass加载类,以下是源码
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
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.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
系统抽象类public abstract class ClassLoader中的findClass方法没有具体实现,只是抛出异常
URLClassLoader实现了findClass方法
分析两个自定义的加载器:
CompileClassLoader extends ClassLoader
HotSwapClassLoader extends URLClassLoader (URLClassLoader也继承自ClassLoader)
CompileClassLoader 重写的是findClass方法,这种自定义方式还是委派给双亲先加载,只不过实现了
自己的加载 方式即实现了findClass方法
若有个类A希望用自定的CompileClassLoader类加载器加载,
前提是系统加载器尚未加载该类(因为这个 自定义类加载器还是委派了双亲),
否则无法使用自定义的类加载器加载
HotSwapClassLoader 重写的是loadClass方法 这种方式没有委派双亲,
而且直接父类URLClassLoader也实现了findClass方法,
所以推荐使用这种方式自定义类加载器