java SPI機制與雙親委派機制的不同 純原創長文-深入理解Java類加載(雙親委派機制及其破壞 JavaSPI和DubboSPI的區別和聯繫)

 

1、雙親委派機制

1.1 定義

當一個類加載器收到了類加載的請求的時候,他不會直接去加載指定的類,而是把這個請求委託給自己的父加載器去加載。

如果父類爲空,交給bootstrap classloader 加載

如果類還是無法被加載到,則觸發findclass,拋出classNotFoundException(findclass這個方法當前只有一個語句,就是拋出classNotFoundException),如果想自己實現類加載器的話,可以繼承classLoader後重寫findclass方法,加載對應的類)

1.2優點

避免類的重複加載
保護程序安全,防止核心API被隨意篡改

2、SPI(service provider interface)定義:

  SPI是jdk內置的一種服務提供發現機制。可以用來啓用框架擴展和替換組件,主要是被框架的開發人員使用,比如java.sql.Driver接口,常用的關係型數據有Mysql、Oracle、SQLServer、DB2等,這些不同類型的數據庫使用的驅動程序各不相同,那JDK不可能把所有廠商的驅動都實現,只能制定一個標準接口,其他不同廠商可以針對同一接口做出不同的實現,各個數據庫廠商根據標準來實現自己的驅動,這就是SPI機制。

 

 

下面看下Mysql的Driver,以com.mysql.cj.jdbc.Driver 爲例

 

 

 

 META-INF目錄的作用是相當於信息包,用來配置應用程序、擴展程序、類加載器和服務manifest.mf文件,在打包時自動生成。

 

其中manifest.mf裏面描述了程序的基本信息、Main-Class的入口、jar依賴路徑Class-Path

而META-INFO/services 的作用是實現接口循環實現類的功能, 除了jdbc模塊的方案(Driver)之外,還有日誌模塊的方案(l4j),xml解析模塊等。

 

回到正題:

 com.mysql.cj.jdbc.Driver的源碼需要往DriverManager進行註冊

最終如下圖所示,需要往 registeredDrivers 裏面進行添加

 

 

而registeredDrivers 變量在 DriverManager 靜態初始化的時候會進行調用把真實的類進行加載出來

 

 

例子

創建一個 interface 接口

 

package com.zhianchen.mysqlremark.springboottest.spi;
/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 11:25
 */

public interface UserService {
     void login();
}

 

 

 

 

實現

package com.zhianchen.mysqlremark.springboottest.spi.Impl;

import com.zhianchen.mysqlremark.springboottest.spi.UserService;

/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 11:26
 */

public class AppUserLoginServiceImpl implements UserService {
    @Override
    public void login() {
        System.out.println("AppUserLoginServiceImpl");
    }
}
package com.zhianchen.mysqlremark.springboottest.spi.Impl;

import com.zhianchen.mysqlremark.springboottest.spi.UserService;

/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 11:26
 */

public class PCUserLoginServiceImpl implements UserService {
    @Override
    public void login() {
        System.out.println("PCUserLoginServiceImpl");
    }
}

 

然後在resources 創建目錄 META-INF.services  (注意:這裏是services 而不是service!!!!!)

創建文件 com.zhianchen.mysqlremark.springboottest.spi.UserService  (這裏的文件名要對應UserService包

裏面的內容

com.zhianchen.mysqlremark.springboottest.spi.Impl.PCUserLoginServiceImpl
com.zhianchen.mysqlremark.springboottest.spi.Impl.AppUserLoginServiceImpl

 

創建一個Test

/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 14:02
 */
public class SpiTest {
    public static void main(String[] args) {
        ServiceLoader<UserService> serviceLoader= ServiceLoader.load(UserService.class);
        for (UserService userService:serviceLoader
             ) {
            userService.login();
        }
    }
}

 

之前的結果是

PCUserLoginServiceImpl
AppUserLoginServiceImpl

 

參考

純原創長文-深入理解Java類加載(雙親委派機制及其破壞 JavaSPI和DubboSPI的區別和聯繫)

https://www.cnblogs.com/masaike/p/15490402.html

META-INF 作用

Java SPI詳解

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章