搜尋

首頁  >  問答  >  主體

java - spring ioc中为什么使用classloader,而不是Class.forName

阿神阿神2802 天前577

全部回覆(1)我來回復

  • 怪我咯

    怪我咯2017-04-18 10:53:03

    Class.forName 和 ClassLoader.loadClass 的差別

    類別載入

    為了弄清楚 Class.forNameClassLoader.loadClass 的區別, 首先我們需要了解 JVM 中類加載的步驟.
    類的加載可以分為如下幾步

    • 載入: 透過類別的全限定名取得到類別的二進位流, 然後載入到 JVM 中

    • 驗證: 確保Class 檔案的位元組流中包含的資訊符合虛擬機器的要求, 並且不會危害虛擬機器的安全

    • 準備: 為類別變數分配記憶體空間並設定類變初始值

    • 解析

    • 初始化: 根據使用者指定的程式碼初始化欄位和其他資源, 執行 static 區塊.

    Class.forName

    當我們通過:

    Class.forName("com.test.MyObj")

    來取得一個Class 時, 那麼其實相當於呼叫了Class.forName(className, true, currentLoader), 這個方法的第二個參數表示是否需要初始化類別. 我們設定為 true, 因此Class.forName 取得到Class 物件時, 會自動對類別進行初始化的.Class.forName(className, true, currentLoader), 这个方法的第二个参数表示是否需要初始化类. 我们设置为 true, 因此 Class.forName 获取到 Class 对象时, 会自动对类进行初始化的.
    并且 Class.forName 加载类的 ClassLoader 和调用 Class.forName並且Class.forName 載入類別的ClassLoader 和呼叫Class.forName 所在的類別的ClassLoader相同.

    ClassLoader.loadClass

    Class.forName 不同, 預設情況下ClassLoader.loadClass 並不會初始化類別, 即類別載入的初始化 步驟沒有執行, 因此類別中的靜態程式碼區塊不會執行.Class.forName 不同, 默认情况下 ClassLoader.loadClass 并不会初始化类, 即类加载的 初始化 步骤没有执行, 因此类中的静态代码块不会执行.
    并且使用 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 不需要執行類中的初始化代碼, 可以加快加載速度, 把類的初始化工作留到實際使用到這個類別的時候.

    回覆
    0
  • 取消回覆