java - spring ioc中為什么使用classloader,而不是Class.forName
問題描述
spring ioc中為什么使用classloader,而不是Class.forName這樣使用有什么好處?這兩者有什么本質(zhì)上的區(qū)別?問題解答
回答1:Class.forName 和 ClassLoader.loadClass 的區(qū)別類加載為了弄清楚 Class.forName 和 ClassLoader.loadClass 的區(qū)別, 首先我們需要了解 JVM 中類加載的步驟.類的加載可以分為如下幾步
加載: 通過類的全限定名獲取到類的二進(jìn)制流, 然后加載到 JVM 中
驗(yàn)證: 確保Class 文件的字節(jié)流中包含的信息符合虛擬機(jī)的要求, 并且不會(huì)危害虛擬機(jī)的安全
準(zhǔn)備: 為類變量分配內(nèi)存空間并設(shè)置類變初始值
解析
初始化: 根據(jù)用戶指定的代碼初始化字段和其他資源, 執(zhí)行 static 塊.
Class.forName當(dāng)我們通過:
Class.forName('com.test.MyObj')
來獲取一個(gè) Class 時(shí), 那么其實(shí)相當(dāng)于調(diào)用了 Class.forName(className, true, currentLoader), 這個(gè)方法的第二個(gè)參數(shù)表示是否需要初始化類. 我們?cè)O(shè)置為 true, 因此 Class.forName 獲取到 Class 對(duì)象時(shí), 會(huì)自動(dòng)對(duì)類進(jìn)行初始化的.并且 Class.forName 加載類的 ClassLoader 和調(diào)用 Class.forName 所在的類的 ClassLoader 相同.
ClassLoader.loadClass與 Class.forName 不同, 默認(rèn)情況下 ClassLoader.loadClass 并不會(huì)初始化類, 即類加載的 初始化 步驟沒有執(zhí)行, 因此類中的靜態(tài)代碼塊不會(huì)執(zhí)行.并且使用 ClassLoader.loadClass 時(shí), 我們可以指定不同的 ClassLoader. 例如:
ClassLoader.getSystemClassLoader().loadClass('com.test.MyObj');一個(gè)例子
public class MyObj { static {System.out.println('MyObj class init.'); }}
public class Test implements Cloneable, Serializable { public static void main(String[] args) throws Exception {Class.forName('com.test.MyObj');// ClassLoader.getSystemClassLoader().loadClass('com.test.MyObj'); }}
那么上面的代碼中, Class.forName('com.test.MyObj') 的調(diào)用會(huì)觸發(fā) MyObj 的靜態(tài)代碼塊的執(zhí)行, 而 ClassLoader.getSystemClassLoader().loadClass('com.test.MyObj'); 并不會(huì).
這樣使用有什么好處?我個(gè)人猜測(cè), 應(yīng)該和 Spring IoC 的 Lazy loading 有關(guān), Spring IoC 為了加快初始化速度, 因此大量使用了延時(shí)加載技術(shù). 而使用 classloader 不需要執(zhí)行類中的初始化代碼, 可以加快加載速度, 把類的初始化工作留到實(shí)際使用到這個(gè)類的時(shí)候.
