java - spring ioc中為什么使用classloader,而不是Class.forName
問題描述
spring ioc中為什么使用classloader,而不是Class.forName這樣使用有什么好處?這兩者有什么本質上的區別?問題解答
回答1:Class.forName 和 ClassLoader.loadClass 的區別類加載為了弄清楚 Class.forName 和 ClassLoader.loadClass 的區別, 首先我們需要了解 JVM 中類加載的步驟.類的加載可以分為如下幾步
加載: 通過類的全限定名獲取到類的二進制流, 然后加載到 JVM 中
驗證: 確保Class 文件的字節流中包含的信息符合虛擬機的要求, 并且不會危害虛擬機的安全
準備: 為類變量分配內存空間并設置類變初始值
解析
初始化: 根據用戶指定的代碼初始化字段和其他資源, 執行 static 塊.
Class.forName當我們通過:
Class.forName('com.test.MyObj')
來獲取一個 Class 時, 那么其實相當于調用了 Class.forName(className, true, currentLoader), 這個方法的第二個參數表示是否需要初始化類. 我們設置為 true, 因此 Class.forName 獲取到 Class 對象時, 會自動對類進行初始化的.并且 Class.forName 加載類的 ClassLoader 和調用 Class.forName 所在的類的 ClassLoader 相同.
ClassLoader.loadClass與 Class.forName 不同, 默認情況下 ClassLoader.loadClass 并不會初始化類, 即類加載的 初始化 步驟沒有執行, 因此類中的靜態代碼塊不會執行.并且使用 ClassLoader.loadClass 時, 我們可以指定不同的 ClassLoader. 例如:
ClassLoader.getSystemClassLoader().loadClass('com.test.MyObj');一個例子
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') 的調用會觸發 MyObj 的靜態代碼塊的執行, 而 ClassLoader.getSystemClassLoader().loadClass('com.test.MyObj'); 并不會.
這樣使用有什么好處?我個人猜測, 應該和 Spring IoC 的 Lazy loading 有關, Spring IoC 為了加快初始化速度, 因此大量使用了延時加載技術. 而使用 classloader 不需要執行類中的初始化代碼, 可以加快加載速度, 把類的初始化工作留到實際使用到這個類的時候.
