1. 程式人生 > >深入類載入器----執行緒上下文類載入器

深入類載入器----執行緒上下文類載入器

            深入類載入器(四)----執行緒上下文切換類載入器

                      執行緒上下文類載入器


我們知道在java中的載入器的載入模式是雙親委託模式,這種模式是遵從父類優先的原則。

但是在一些場合中,這種雙親委託機制反而是行不通的。

最典型的是JDBCApi:其實JDBCApi包括倆部分:一部分是oragle公司提供的介面類,一部分是具體的廠商提供的實現類,也就是所謂的driver驅動部分。比如是要使用mysql資料庫的話,那麼就需要載入mysql資料庫的驅動。如果還是按照,雙親委託機制的話,那麼對於oragle公司提供的介面部分就是由拓展類載入器來進行進行載入的。注意,介面也是一種型別,也需要被類載入器進行載入才可以。

我們要明白一點,一般來說,介面和具體的實現應該由同一個的類載入器進行載入。如果是由不同的載入器進行載入的話,那麼就會造成介面找不到具體的實現。這是不行的。

但是至於廠商提供的具體的實現的部分,也就是第三方的jar包,一般是由應用程式類載入器進行載入的。這樣的話,就會使介面和實現的類載入器是不一樣的。這樣是不行的。為了解決這個問題,就拋棄了雙親委託機制,而提出了執行緒上下文類載入器。在api+spi的模組框架下,很多的底層的實現都是使用了執行緒上下文類載入器。這是要注意的。線上程上下文類載入器中,

我們可以自定義類載入器,並且指定這種類載入器不適用雙親委託機制,這樣的話,就可以使介面和具體的實現的載入器是一樣的。。

從而就解決了這個問題。

下面看一個例子:

package com.lg.test;

/*這就是執行緒上下文切換類載入器這主要是為了防止Api+spi的錯誤而特定使用的*/

/*比如說,JDBC中,介面API是由oragle公司提供的,這些介面API一般是由Boot類載入器進行載入的*/

/*但是具體的實現是由App進行載入的。這樣的話,就會使介面找不到實現。就會出現錯誤。所以我們要

 * 使用執行緒上下文切換來進行,使載入的類載入器都是相同的。這是要注意的*/

public class ThreadClassLoader {

    public static void main(String[] args) {

        ClassLoader loader=ThreadClassLoader.class.getClassLoader();

        System.out.println(loader);

        ClassLoader loader1 = Thread.currentThread().getContextClassLoader();

        System.out.println(loader1);

        Thread.currentThread().setContextClassLoader(new FileClassLoader("c://myjava"));

        System.out.println(Thread.currentThread().getContextClassLoader());

        try {

     Class<?>  c= Thread.currentThread().getContextClassLoader().loadClass("com.lg.test.Demo02");

            System.out.println(c);

            System.out.println(c.getClassLoader());

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

    }

}

最後的輸出的結果是:

sun.misc.Launcher$AppClassLoader@4e0e2f2a

sun.misc.Launcher$AppClassLoader@4e0e2f2a

com.lg.test.FileClassLoader@15db9742

class com.lg.test.Demo02

sun.misc.Launcher$AppClassLoader@4e0e2f2a

為什麼最後輸出的還是應用程式的類載入器呢?因為這個自定義的類載入器內部還是使用了雙親委託機制,

但是我們也可以自己通過程式碼來控制它不是雙親委託機制的。這部分可以根據具體的需要來進行實現。