欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中SPI機制的實現(xiàn)詳解

 更新時間:2024年01月29日 10:31:53   作者:學(xué)而不思則忘  
SPI(Service?Provider?Interface),是?JDK?內(nèi)置的一種服務(wù)提供發(fā)現(xiàn)機制,可以用來啟用框架擴展和替換組件,下面我們就來看看Java中SPI機制的具體實現(xiàn)

簡介

SPI(Service Provider Interface),是 JDK 內(nèi)置的一種服務(wù)提供發(fā)現(xiàn)機制,可以用來啟用框架擴展和替換組件,核心思想是解耦。比如java.sql.Driver接口,其他不同廠商可以針對同一接口做出不同的實現(xiàn),MySQL 和 PostgreSQL 都有不同的實現(xiàn)提供給用戶。

當(dāng)服務(wù)提供者提供了一種接口的實現(xiàn)后,需要在 classpath 下的 META-INF/services/ 目錄下創(chuàng)建一個以服務(wù)接口命名的文件,文件的內(nèi)容就是接口的具體實現(xiàn)類。

當(dāng)使用該服務(wù)時,掃描 META-INF/services/ 下配置文件,就可以加載類使用該服務(wù)。JDK 中查找服務(wù)的工具類是:java.util.ServiceLoader。

以 MySQL 驅(qū)動為例:

源碼實現(xiàn)

以上面連接數(shù)據(jù)庫作為示例,看看 java8 SPI 怎么實現(xiàn)的。

入口在 java.sql.DriverManager 類中:

    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

    private static void loadInitialDrivers() {
        String drivers;
        try {
            drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    return System.getProperty("jdbc.drivers");
                }
            });
        } catch (Exception ex) {
            drivers = null;
        }
        // If the driver is packaged as a Service Provider, load it.
        // Get all the drivers through the classloader
        // exposed as a java.sql.Driver.class service.
        // ServiceLoader.load() replaces the sun.misc.Providers()

        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {

                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

                /* Load these drivers, so that they can be instantiated.
                 * It may be the case that the driver class may not be there
                 * i.e. there may be a packaged driver with the service class
                 * as implementation of java.sql.Driver but the actual class
                 * may be missing. In that case a java.util.ServiceConfigurationError
                 * will be thrown at runtime by the VM trying to locate
                 * and load the service.
                 *
                 * Adding a try catch block to catch those runtime errors
                 * if driver not available in classpath but it's
                 * packaged as service and that service is there in classpath.
                 */
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });

        println("DriverManager.initialize: jdbc.drivers = " + drivers);

        if (drivers == null || drivers.equals("")) {
            return;
        }
        String[] driversList = drivers.split(":");
        println("number of Drivers:" + driversList.length);
        for (String aDriver : driversList) {
            try {
                println("DriverManager.Initialize: loading " + aDriver);
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }
    }

上面的代碼主要步驟是:

  • 從系統(tǒng)變量中獲取有關(guān)驅(qū)動的定義。
  • 使用 SPI 來獲取驅(qū)動的實現(xiàn)。
  • 遍歷使用 SPI 獲取到的具體實現(xiàn),實例化各個實現(xiàn)類。
  • 根據(jù)第一步獲取到的驅(qū)動列表來實例化具體實現(xiàn)類。

主要關(guān)注第2,3步,第 2 步使用 SPI 獲取驅(qū)動的實現(xiàn),對應(yīng)實現(xiàn):

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);

這里沒有去 META-INF/services 目錄下查找配置文件,也沒有加載具體實現(xiàn)類,只是封裝了接口類型和類加載器,并初始化了一個迭代器。

接著看第三步,遍歷使用 SPI 獲取到的具體實現(xiàn),實例化各個實現(xiàn)類,對應(yīng)的代碼如下:

// 獲取迭代器
Iterator<Driver> driversIterator = loadedDrivers.iterator();
// 遍歷所有的驅(qū)動實現(xiàn)
while(driversIterator.hasNext()) {
    driversIterator.next();
}

在遍歷的時候,首先調(diào)用driversIterator.hasNext()方法,這里會搜索 classpath 下以及jar包中所有的META-INF/services目錄下的java.sql.Driver文件,并找到文件中的實現(xiàn)類的名字,此時并沒有實例化具體的實現(xiàn)類。

然后是調(diào)用driversIterator.next();方法,此時就會根據(jù)驅(qū)動名字具體實例化各個實現(xiàn)類了。具體的掃描加載源碼見java.util.ServiceLoader 方法。

以上就是Java中SPI機制的實現(xiàn)詳解的詳細內(nèi)容,更多關(guān)于Java SPI機制的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于Java驗證jwt token代碼實例

    基于Java驗證jwt token代碼實例

    這篇文章主要介紹了基于Java驗證jwt token代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • Springboot中@scheduled注解解析

    Springboot中@scheduled注解解析

    這篇文章主要介紹了Springboot中@scheduled注解解析,定時任務(wù)就是在指定時間執(zhí)行程序,或周期性執(zhí)行計劃任務(wù),Java中實現(xiàn)定時任務(wù)的方法有很多,本文從從JDK自帶的一些方法來實現(xiàn)定時任務(wù)的需求,需要的朋友可以參考下
    2023-09-09
  • mybatis test標(biāo)簽如何判斷值是否相等

    mybatis test標(biāo)簽如何判斷值是否相等

    這篇文章主要介紹了mybatis test標(biāo)簽判斷值是否相等的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java使用JNA調(diào)用DLL文件

    Java使用JNA調(diào)用DLL文件

    JNA(Java?Native?Access)是一個在?Java?中調(diào)用本地代碼的開源框架,提供了一種簡單、高效的方式來訪問本地動態(tài)鏈接庫,下面我們來看看Java如何使用JNA調(diào)用DLL文件吧
    2024-12-12
  • SpringBoot+微信小程序?qū)崿F(xiàn)文件上傳與下載功能詳解

    SpringBoot+微信小程序?qū)崿F(xiàn)文件上傳與下載功能詳解

    這篇文章主要為大家介紹了SpringBoot整合微信小程序?qū)崿F(xiàn)文件上傳與下載功能,文中的實現(xiàn)步驟講解詳細,快跟隨小編一起學(xué)習(xí)一下吧
    2022-03-03
  • springboot引入druid解析sql的過程

    springboot引入druid解析sql的過程

    在開發(fā)中,有時我們可能會需要獲取SQL中的表名,那么因為不同的數(shù)據(jù)源類型SQL會存在部分差異,那么我們就可以使用alibaba 的druid包實現(xiàn)不同的數(shù)據(jù)源類型的sql解析,需要的朋友可以參考下
    2023-08-08
  • 詳解Spring學(xué)習(xí)總結(jié)——Spring實現(xiàn)AOP的多種方式

    詳解Spring學(xué)習(xí)總結(jié)——Spring實現(xiàn)AOP的多種方式

    這篇文章主要介紹了詳解Spring學(xué)習(xí)總結(jié)——Spring實現(xiàn)AOP的多種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • 這一次搞懂Spring事務(wù)注解的解析方式

    這一次搞懂Spring事務(wù)注解的解析方式

    這篇文章主要介紹了這一次搞懂Spring事務(wù)注解的解析方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • java對象池管理方式common-pool2使用

    java對象池管理方式common-pool2使用

    這篇文章主要為大家介紹了java對象池common-pool2使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • MyBatis異常-Property ''configLocation'' not specified, using default MyBatis Configuration

    MyBatis異常-Property ''configLocation'' not specified, using d

    今天小編就為大家分享一篇關(guān)于MyBatis異常-Property 'configLocation' not specified, using default MyBatis Configuration,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03

最新評論