java中的classloader
類載入器,是java安全的一部分,通常情況下我們是不用關心類的載入過程的,但這是通常情況下,非通常的情況下,我們要關心類的載入過程。並且要適度的控制類的載入過程。下面就結合我在開發過程中遇到的一個問題,討論一下類載入器的相關知識。
在core java中,類載入器歸類為安全的第一道門檻。因為java天生的類載入機制,避免了類的重複載入。保證了同一個類只被載入一次的這個要求。
介紹載入機制前,我們先來說一下幾個名詞(一家之言,具體定義請google一下)。
類載入器:將類載入進jvm中的一個工具。類的來源可以是網路、本地檔案,資料庫。(看一下URLclassLoader就可以知道,其實只要有一個完整的流,就可以根據該流將類載入至虛擬機器)
雙親委託:是指在標準情況下,類載入器在需要載入一個類時,會先委託他的雙親載入器進行載入。如果雙親能載入到對應的類,則使用雙親的載入的類,如果雙親不能載入,再自己進行載入。
BootstrapClassLoader:引導類載入器,是載入虛擬機器核心庫的載入器。
ExtClassLoader:用來載入jre/lib/ext目錄下的jar包。
AppClassLoader:載入設定的classpath路徑下的jar包。
URLclassLoader:j2SE包含的一個類載入器,在專案中自定義類載入器,整合該類載入器通常是最佳的選擇。
介紹完了名詞:下面我就結合我的實際經驗,簡單介紹一下我遇到的問題。
事情是醬紫的。一個軟體供應商為兩個使用者提供了不同版本的軟體,而我方的軟體需要在同一個應用中同事連線到這兩個使用者在連線到使用者的過程中,需要使用使用者對應的jar包。這就導致了在同一個應用中,需要以來不同版本的一個jar包,並且jar包中大部分內容是相同的(有許多相同名稱和內容的類)。
問題出現了,這是一個類載入器解決的典型問題。
我最初解決這個問題的方案,有點複雜了。我最初想的是通過自定義類載入器,破壞類載入固有的雙親委託機制。然後用特定的類載入器,去載入需要的類。保證先用類載入器內部的類,如果內部沒有,才通過父載入器去載入。
最初這樣做的目的,是這樣指定容易。但是開發量,安全性,可讀性都不高。因為這麼做破壞了雙親委託機制,會導致類的多次載入。
在經過幾次重構以後。最終確定的方案為:
將兩個不同版本的jar包,放在一箇中加件不能自動載入的地方,這樣,整個應用中就沒有對應的類。如果不載入,肯定是不能用的。解決這個問題的方法,就是在需要用到jar包內的類時。由指定的類去載入對應的jar包中的類。
就是在需要的時候由指定的類載入器載入指定的類。這樣做的好處就是,沒有破壞類的載入機制--雙親委託、保證了在區域內類的唯一性--即在使用某個類的上下文中,任何一個類只被載入過一次。至此,問題解決。