您好,登錄后才能下訂單哦!
這篇“Java怎么自定義類加載器實現類隔離”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java怎么自定義類加載器實現類隔離”文章吧。
某服務需要連接操作多種組件(每種組件可能有多個版本),如kafka、mongodb、es、mysql等等,并且后續需要適配更多的組件。
主要難點:連接操作多組件多版本,且同種組件的不同版本所依賴的jar包可能不一樣,操作源碼也可能發生改變,項目無法直接依賴jar包,會產生類沖突
由于每種組件的不同版本所依賴的jar包不同,我們可以借鑒tomcat的實現方式,通過自定義類加載器打破雙親委派機制來實現類隔離,從而達到操作多組件多版本的目的。
針對每一種組件我們創建一個目錄,比如/data/kafka、/data/mongodb、/data/es等,且每種組件的不同版本創建對應的子目錄,比如/data/kafka/0.10、/data/kafka/0.11,目錄結構如下
| ----/data
| --------/kafka
| ------------/0.10
| ------------/0.11
| --------/mysql
| ------------/5.7
| ------------/8.0
| ...
把每種組件不同版本對應的依賴包放在各個子目錄下面。
在common公共模塊中定義一個接口AbstractOperator,該接口定義一些通用方法,如下:
public interface Operator { /** * 測試連接 * @param connectionInfo * @return */ boolean testConnection(String connectionInfo); /** * 獲取組件版本 * @return */ String getVersion(String connectionInfo); }
再定義各種組件的接口,如KafkaOperator、MysqlOperator等,使其繼承該通用接口。組件接口內部包含一些組件自身的操作,如KafkaOperator中定義了getTopics、createTopic、deleteTopic等方法。代碼如下:
public interface KafkaOperator extends Operator{ /** * 獲取topic列表 * @param connectionInfo * @return */ List<String> getTopics(String connectionInfo); /** * 創建topic * @param connectionInfo * @param topic * @return */ boolean createTopic(String connectionInfo, String topic); /** * 刪除topic * @param connectionInfo * @param topic * @return */ boolean deleteTopic(String connectionInfo, String topic); }
大致步驟如下:
1.針對每種組件的不同版本,可以在項目下新建一個模塊,該模塊依賴common公共模塊
2.創建入口類com.kamier.Entry(所有組件的不同版本的入口類的全限定名統一為com.kamier.Entry),并實現對應的組件接口,比如Kafka的0.10版本,那么就實現KafkaOperator接口。
3.編寫業務邏輯代碼
public class Entry implements KafkaOperator { @Override public List<String> getTopics(String connectionInfo) { return null; } @Override public boolean createTopic(String connectionInfo, String topic) { return false; } @Override public boolean deleteTopic(String connectionInfo, String topic) { return false; } @Override public boolean testConnection(String connectionInfo) { return false; } @Override public String getVersion(String connectionInfo) { return null; } }
4.打成jar包
5.將jar包放在對應的目錄下,與依賴包同級,如/data/kafka/0.10
經過前面的準備工作,組件的每個版本的目錄下都有了相應的依賴包和業務包。
開始編寫一個自定義類加載器繼承URLClassLoader,重寫loadClass方法,優先加載當前類加載器路徑下的class來打破雙親委派模式,代碼如下
public static class MyClassLoader extends URLClassLoader { public MyClassLoader(URL[] urls) { super(urls); } public Class<?> loadClass(String name) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 先檢查當前類加載器是否已經裝載該類 Class<?> c = findLoadedClass(name); if (c == null) { try { // 在當前類加載器的路徑下查找 c = findClass(name); } catch (ClassNotFoundException e) { // 說明在當前類加載器的路徑下沒有找到 } if (c == null) { // 走雙親委派機制 if (getParent() != null) { c = getParent().loadClass(name); } } } return c; } } }
針對每種組件的不同版本,我們創建與其對應的自定義類加載器,并將該版本對應目錄下的所有jar包(包括依賴包和業務包)的URL傳入。
步驟如下:
當我們從頁面上接收到一個獲取Kafka(版本為0.10)topic列表的請求時,先判斷是否已經初始化過Kafka(0.10版本)的類加載器,如果還未初始化,則進行類加載器的初始化。
URL[] urls = null; File dir = new File("/data/kafka/0.10"); if (dir.isDirectory()) { File[] files = dir.listFiles(); urls = new URL[files.length]; for (int i = 0; i < files.length; i++) { urls[i] = files[i].toURL(); } } MyClassLoader contextClassLoader = new MyClassLoader(urls);
通過類加載器加載入口類com.kamier.Entry并實例化,通過反射調用對應的方法(組件與其對應的方法列表可以統一維護在數據庫中)。
Class loadClass = contextClassLoader.loadClass("com.kamier.Entry"); Object entry = loadClass.newInstance(); Method method = loadClass.getDeclaredMethod("getTopics"); List<String> a = (List) method.invoke(entry, 參數);
獲取到結果并返回。
以上就是關于“Java怎么自定義類加載器實現類隔離”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。