一.ContextClassLoader
- ContextClassLoader只是一个逻辑上的概念,在Java Api里并没有一个叫ContextClassLoader的类。
- JVM默认类加载体系已经能满足大部分情况的使用了,那为什么还需要ContextClassLoader呢。但有时候这样的加载体系并不能满足要求,比喻需要动态加载应用程序开发人员提供的资源时。考虑JDBC的实现,JDK中的JDBC Api是由BootStrap加载的,当我们确定使用某一厂商的JDBC实现时,实现类也会由BootstrapLoader加载,显然BootstrapLoader是加载不了的。于是就出现了ContextClassLoader这个概念。JDBC Api里使用ContextClassLoader去加载实现类,默认情况ContextClassLoader就是AppClassLoader(参考http://zy19982004.iteye.com/blog/1983236),刚好可以加载位于classpath下的实现类。
- 再说的清楚一点,ContextClassLoader就是Thread的一个属性,提供了get和set方法,因此任何地方都可以设置并获得这个ClassLoader。
private ClassLoader contextClassLoader;
- 在没有显示setContextClassLoader的时候,getContextClassLoader默认返回的是该线程的父线程的ClassLoader。
public void setContextClassLoader(ClassLoader cl){} public ClassLoader getContextClassLoader() {}
- 其实还有一个办法,把AppClassLoader保存起来,当BootstrapLoader加载不到实现类时,用AppClassLoader去加载。
二.学习例子
package com.jyz.study.jdk.classLoader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* 演示ContextClassLoader的使用
* @author JoyoungZhang@gmail.com
*
*/
public class ContextClassLoaderTest {
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
System.out.println("MainClass getClassLoader: " + ContextClassLoaderTest.class.getClassLoader());
System.out.println("MainClass getContextClassLoader: " + Thread.currentThread().getContextClassLoader());
Thread innerThread1 = new InnerThread1();
innerThread1.start();
}
}
class InnerThread1 extends Thread{
@Override
public void run() {
try {
URL[] urls = new URL[1];
urls[0] = new URL("jar:file:/E:/GoogleCode/platform-components/trunk/SourceCode/component-core/target/component-core-1.0.jar!/");
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class<?> clazz = urlClassLoader.loadClass("com.jyz.component.core.collection.Tuple");
System.out.println(clazz.newInstance());
System.out.println("InnerThread1 getClassLoader: " + clazz.getClassLoader());
System.out.println("InnerThread1 getContextClassLoader: " + Thread.currentThread().getContextClassLoader());
this.setContextClassLoader(urlClassLoader);
Thread innerThread2 = new InnerThread2();
innerThread2.start();
}catch (MalformedURLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class InnerThread2 extends Thread{
@Override
public void run() {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
classLoader.loadClass("com.jyz.component.core.collection.Triple");
System.out.println("InnerThread2 getContextClassLoader: " + Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
console output:
MainClass getClassLoader: sun.misc.Launcher$AppClassLoader@f6a746
MainClass getContextClassLoader: sun.misc.Launcher$AppClassLoader@f6a746
Tuple[t1:null, t2:null]
InnerThread1 getClassLoader: java.net.URLClassLoader@f9f9d8
InnerThread1 getContextClassLoader: sun.misc.Launcher$AppClassLoader@f6a746
InnerThread2 getContextClassLoader: java.net.URLClassLoader@f9f9d8
注释掉36行时console output:
MainClass getClassLoader: sun.misc.Launcher$AppClassLoader@f6a746
MainClass getContextClassLoader: sun.misc.Launcher$AppClassLoader@f6a746
Tuple[t1:null, t2:null]
InnerThread1 getClassLoader: java.net.URLClassLoader@f9f9d8
InnerThread1 getContextClassLoader: sun.misc.Launcher$AppClassLoader@f6a746
java.lang.ClassNotFoundException: com.jyz.component.core.collection.Triple
...异常栈信息