前言:
我們都知道判斷兩個類是不是同一個,要根據類加載器和全限定名。這是為什么呢?為什么不同的類加載器加載同一個類是不同的呢?
答案就是,不同的類加載器所加載的類在方法區的存儲空間是不同的即InstanceKlass的不同。不同類加載器之間的空間是分隔開的。同一個類在一個類加載器中只會加載一次。
雙親委派的弊端,無法做到不委派,也無法向下委派。
沙箱安全:
雖然JVM讓我們用一些方式打破雙親委派,但是對於系統的核心類庫JVM是會進行保護不讓篡改的。如果自己寫了和核心類庫相同的類,在運行的時候會出錯。
一:自定義類加載器打破雙親委派,不委派雙親
我們從上篇中有介紹classLoader.loadClass的時候會進行雙親委派進行加載,如果雙親都找不到指定類會調用findClass方法。
classLoader類中的loadClass有默認的實現就是雙親委派邏輯,findClass沒有默認的實現需要自定義類加載器來實現。
所以如果只是使用一個自定義類加載器而不打破雙親委派,只要繼承ClassLoader來重寫findClass。如果想打破雙親委派,也要重寫loadClass方法了,做到不委派。
二:SPI機制向下委派
SPI ,全稱為 Service Provider Interface,是一種服務發現機制。它通過在ClassPath路徑下的META-INF/services文件夾查找文件,自動加載文件里所定義的類。
這一機制為很多框架擴展提供了可能,比如在Dubbo、JDBC中都使用到了SPI機制。我們先通過一個很簡單的例子來看下它是怎么用的。SPI是實現向下委派的。
1:接口類模塊
就一個接口,讓其它模塊通過Maven引用。
2:第一個接口實現類模塊
只有一個實現類,在resources下面增加META-INF/services文件夾,文件夾下面增加一個文本文件,文件名是實現的接口全路徑,文件里面的內容是實現的類的全路徑。
3:第二個接口實現類模塊
接下來我們開始使用SPI機制
我們在pom中引入第一個實現類模塊:
上述main方法執行的結果就是對應實現類的執行結果。
當引入多個實現類的時候,都可以執行。