您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么破壞Java雙親委派模型”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么破壞Java雙親委派模型”吧!
重寫findClass不會破壞雙親委派模型,同時也驗證了雙親委派模型的正確性。
package com.example.classloader; import org.junit.Test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class TestClassLoader { @Test public void test() { Class<?> class0 = TestClassLoader.class; try { // false System.out.println(class0.getClassLoader() instanceof MyClassLoader); Class<?> class1 = class0.getClassLoader().loadClass("com.example.classloader.TestClassLoader"); ClassLoader classLoader = new MyClassLoader(); Class<?> class2 = classLoader.loadClass("com.example.classloader.TestClassLoader"); // true System.out.println(class0.equals(class1)); // true System.out.println(class1.equals(class2)); // sun.misc.Launcher$AppClassLoader@18b4aac2 System.out.println(class0.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2 System.out.println(class1.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2 System.out.println(class2.getClassLoader()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 自定義一個類加載器從指定磁盤目錄加載類 * 重寫findClass不破壞雙親委派模型 */ public class MyClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) { String myPath = "/Users/lsx/code/demo/target/classes/" + name.replace(".", "/") + ".class"; byte[] classBytes = null; FileInputStream in = null; try { File file = new File(myPath); in = new FileInputStream(file); classBytes = new byte[(int) file.length()]; in.read(classBytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } Class<?> clazz = defineClass(name, classBytes, 0, classBytes.length); return clazz; } } }
重寫loadClass破壞雙親委派模型,父類的加載(Object)也會交由我們自自定義的類加載器加載。而很明顯在我們自定義的加載目錄下是不會有Object.class這個文件的,所以會拋出異常。
/** * 重寫loadClass破壞雙親委派模型 * java.io.FileNotFoundException: /Users/lsx/code/demo/target/classes/java/lang/Object.class (No such file or directory) */ public class MyClassLoader extends ClassLoader { @Override public Class<?> loadClass(String name) { String myPath = "/Users/lsx/code/demo/target/classes/" + name.replace(".", "/") + ".class"; System.out.println(myPath); byte[] classBytes = null; FileInputStream in = null; try { File file = new File(myPath); in = new FileInputStream(file); classBytes = new byte[(int) file.length()]; in.read(classBytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println(); Class<?> clazz = defineClass(name, classBytes, 0, classBytes.length); return clazz; } }
總結:如果不想打破雙親委派模型就重寫ClassLoader類中的findClass()方法即可,無法被父類加載器加載的類最終會通過這個方法被加載。而如果想打破雙親委派模型則需要重寫loadClass()方法。
原生的JDBC中Driver驅動本身只是一個接口,并沒有具體的實現,具體的實現是由不同數據庫類型去實現的。例如,MySQL的mysql-connector-.jar中的Driver類具體實現的。 原生的JDBC中的類是放在rt.jar包的,是由啟動類加載器進行類加載的,在JDBC中的Driver類中需要動態去加載不同數據庫類型的Driver類,而mysql-connector-.jar中的Driver類是用戶自己寫的代碼,那啟動類加載器肯定是不能進行加載的,既然是自己編寫的代碼,那就需要由應用程序啟動類去進行類加載。于是乎,這個時候就引入線程上下文件類加載器(Thread Context ClassLoader)。有了這個東西之后,程序就可以把原本需要由啟動類加載器進行加載的類,由應用程序類加載器去進行加載了。通過線程上下文加載器去加載所需要的SPI代碼,也就是父類加載器請求子類加載器去完成類加載的動作,實際是通過打破了雙親委派模型的層次結構來逆向使用類加載器,違背了雙親委派模型的一般性原則。具體參考以JDBC為例談雙親委派模型的破壞
雙親委派模型的第三次“被破壞”是由于用戶對程序的動態性的追求導致的。為了實現熱插拔、熱部署、模塊化,意思是添加一個功能或減去一個功能不用重啟,只需要把這模塊連同類加載器一起換掉就實現了代碼的熱替換。例如OSGi的出現,在OSGi環境下類加載器不再是雙親委派模型中的樹狀結構,而是進一步發展為網狀結構。
到此,相信大家對“怎么破壞Java雙親委派模型”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。