爲什麼說SPI打破雙親委派機制

爲什麼說SPI打破雙親委派機制

簡單介紹ClassLoader的雙親委派機制:

java類通過Classloader加載,Classloader之間有繼承關係,AppClassLoader繼承ExtClassloader繼承BootstrapClassloader。在類加載時,子加載器會調用父加載器來加載類,如果父加載器不能加載類,纔會交給子加載器來加載;如果子加載器也加載失敗,那麼就報異常。

可以看出雙親委派機制是一種至下而上的加載方式,那麼SPI是如何打破這種關係?
以JDBC加載驅動爲例:
在JDBC4.0之後支持SPI方式加載java.sql.Driver的實現類。SPI實現方式爲,通過ServiceLoader.load(Driver.class)方法,去各自實現Driver接口的lib的META-INF/services/java.sql.Driver文件裏找到實現類的名字,通過Thread.currentThread().getContextClassLoader()類加載器加載實現類並返回實例。

驅動加載的過程大致如上,那麼是在什麼地方打破了雙親委派模型呢?

先看下如果不用Thread.currentThread().getContextClassLoader()加載器加載,整個流程會怎麼樣。

  1. 從META-INF/services/java.sql.Driver文件得到實現類名字DriverA
  2. Class.forName(“xx.xx.DriverA”)來加載實現類
  3. Class.forName()方法默認使用當前類的ClassLoader,JDBC是在DriverManager類裏調用Driver的,當前類也就是DriverManager,它的加載器是BootstrapClassLoader。
  4. 用BootstrapClassLoader去加載非rt.jar包裏的類xx.xx.DriverA,就會找不到
  5. 要加載xx.xx.DriverA需要用到AppClassLoader或其他自定義ClassLoader
  6. 最終矛盾出現在,要在BootstrapClassLoader加載的類裏,調用AppClassLoader去加載實現類

這樣就出現了一個問題:如何在父加載器加載的類中,去調用子加載器去加載類?

  1. jdk提供了兩種方式,Thread.currentThread().getContextClassLoader()和ClassLoader.getSystemClassLoader()一般都指向AppClassLoader,他們能加載classpath中的類
  2. SPI則用Thread.currentThread().getContextClassLoader()來加載實現類,實現在覈心包裏的基礎類調用用戶代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章