Java中所有的类都是由classloader进行加载的。

通常情况下我们不需要显式的去使用类加载器。

但是对于一个web容器而言,通常拥有多个classloader,我们知道,每个classloader所加载的类彼此都是不可见的。比如一个servlet程序,它使用了WEB-INF/lib下面的log4j,而tomcat本身也有一套logj的包。显然对于servlet而言,它是看不到tomcat的log4j,反之亦然。

这一点如何做到?
答案就是线程自身的contextClassLoader。我们知道java代码总是在某个线程中执行的,这个线程所需要的类,则是由它自己的contextClassLoader所加载;当一个线程开启了一个子线程,则子线程会隐式的继承父线程的classloader。这个就是类加载器隔离的关键。

我们可以很容易写一小段代码来证实:
下面这段代码运行后输出是,

main_cl:sun.misc.Launcher$AppClassLoader@1a46e30
MainProc:org.kevx.MyClassLoader@1fb8ee3
SubProc:org.kevx.MyClassLoader@1fb8ee3

证明了上面这个结论。

 

 
   
  1. class MainProc implements Runnable { 
  2.       @Override 
  3.       public void run() { 
  4.              out.println( "MainProc:" + Thread.currentThread().getContextClassLoader()); 
  5.              new Thread( new SubProc()).start(); 
  6.       } 
  7.  
  8. class SubProc implements Runnable { 
  9.       @Override 
  10.       public void run() { 
  11.              out.println( "SubProc:" + Thread.currentThread().getContextClassLoader()); 
  12.       } 
  13.  
  14. class MyClassLoader extends URLClassLoader { 
  15.       public MyClassLoader(URL[] urls) { 
  16.              super(urls); 
  17.       } 
  18.  
  19. public class AsciiUtil { 
  20.        
  21.       public static void main(String[] args) throws Exception { 
  22.              out.println( "main_cl:" + Thread.currentThread().getContextClassLoader()); 
  23.              
  24.             URL url = new URL( "file:///c:/Program Files/Java/jre6/lib" ); 
  25.             MyClassLoader mcl = new MyClassLoader( new URL[]{url}); 
  26.             Thread. currentThread().setContextClassLoader(mcl); 
  27.              
  28.              new Thread( new MainProc()).start(); 
  29.       } 
  30.