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
證明了上面這個結論。
- class MainProc implements Runnable {
- @Override
- public void run() {
- out.println( "MainProc:" + Thread.currentThread().getContextClassLoader());
- new Thread( new SubProc()).start();
- }
- }
- class SubProc implements Runnable {
- @Override
- public void run() {
- out.println( "SubProc:" + Thread.currentThread().getContextClassLoader());
- }
- }
- class MyClassLoader extends URLClassLoader {
- public MyClassLoader(URL[] urls) {
- super(urls);
- }
- }
- public class AsciiUtil {
- public static void main(String[] args) throws Exception {
- out.println( "main_cl:" + Thread.currentThread().getContextClassLoader());
- URL url = new URL( "file:///c:/Program Files/Java/jre6/lib" );
- MyClassLoader mcl = new MyClassLoader( new URL[]{url});
- Thread. currentThread().setContextClassLoader(mcl);
- new Thread( new MainProc()).start();
- }
- }