SPI機制是如何規避雙親委派機制的?

来源:https://www.cnblogs.com/daihang2366/archive/2023/08/29/17665965.html
-Advertisement-
Play Games

# SPI是如何規避雙親委派機制的? # 1、何為雙親委派機制? > 雙親委派機制是什麼? 雙親委派機制指的是Java中類載入機制的特性。 > 雙親委派機制是作用於什麼地方? 雙親委派機制主要作用於類載入的時候。 > 類載入器 首先需要清晰的知道,雙親委派機制指的是類載入的特性。在瞭解其特性之前,我 ...


SPI是如何規避雙親委派機制的?

1、何為雙親委派機制?

雙親委派機制是什麼?

雙親委派機制指的是Java中類載入機制的特性。

雙親委派機制是作用於什麼地方?

雙親委派機制主要作用於類載入的時候。

類載入器

首先需要清晰的知道,雙親委派機制指的是類載入的特性。在瞭解其特性之前,我們需要先瞭解類載入器有哪些(不考慮自定義載入器的情況)。

載入器 解釋
BootStrap載入器 最為頂層的載入器,負責載入System.getProperty("sun.boot.class.path")下的Jar包,主要是jre\lib目錄下的內容。該類載入器為C實現,在Java中無法獲取
Ext類載入器 擴展類載入器,負責載入System.getProperty("java.ext.dirs")下的Jar包,主要是jre\lib\ext下的內容。在Java中對應ExtClassLoader(註意此處以jdk8為例,jdk11中有所改變)。
App類載入器 應用類載入器,負責載入System.getProperty("java.class.path")下的Jar包,主要是自身程式載入的包。在Java中對應AppClassLoader(註意此處以jdk8為例,jdk11中有所改變)。

類載入器之間的結構如何:

可以看出來,App類載入器是最小的一層,也是我們開發用戶接觸最多的一層,越往上載入的類就越核心。

雙親委派機制是什麼樣的結構?

雙親委派機制其實就是描述類載入器載入類的順序及其特點。

我們開發者需要去載入類的場景每天都在接觸,例如在代碼中new Car(我們自己的類),此時就是需要去載入這個類。在觸發載入類的時候,開發者處於載入器的最低層。那麼就可以看作成:App類載入器去載入Car這個類

而實際上的載入順序是這樣的:

App類載入器--通知-->Ext類載入器--通知-->BootStrap類載入器

BootStrap類載入器--發現找不到該類,則向下返回-->Ext類載入器--發現找不到該類,繼續向下返回-->App類載入器(當前類載入器如果找不到該類則拋出異常,否則載入成功)

上述為雙親委派機制載入類時的順序,其特點為先向上通知到最頂層,再由最頂層往下嘗試,直到成功載入或到達發送載入類請求的載入器。

這種載入特點最大的作用如下:

安全性:由於Java核心類均有BootStrap載入器、Ext載入器去載入,再加上這種載入類的特性,可以有效防止Java核心類被篡改,正常的Java應用無法修改核心類實現。不僅可以應用在Java核心類中,當我們的應用是插件式時,此方式也可以防止插件中篡改主程式的代碼。

2、SPI是什麼?

上面我們講述了雙親委派機制,現在要講述SPI。

SPI是什麼?

SPI(Service Provider Interface)是JDK內置的一種服務提供發現機制,可以用來啟用框架擴展和替換組件,主要是被框架的開發人員使用。

例如資料庫驅動中java.sql.Driver介面,其他不同廠商可以針對同一介面做出不同的實現,MySQL和PostgreSQL都有不同的實現提供給用戶,而Java的SPI機制可以為某個介面尋找服務實現。Java中SPI機制主要思想是將功能實現剔除到程式之外,這針對與模塊化解耦有很大的作用。

例如下圖:

除資料庫驅動以外,例如日誌框架、Dubbo等也涉及到SPI機制。

在上圖中,例如當我們需要具體Driver實現的時候,直接通過JDK的API:

ServiceLoader<java.sql.Driver> serviceLoader = ServiceLoader.load(java.sql.Driver.class);
for (java.sql.Driver driver : serviceLoader) {
     // mysql、pg、oracle、db2等
}

註意,SPI機制存在一些約定,這些約束如下:

  1. 三方介面需在META-INF/services/${interface_name}文件中列舉實現類,每一個實現類為一行。例如資料庫這,那麼示例如下:

    META-INF/services/java.sql.Driver

com.mysql.cj.jdbc.Driver
org.postgresql.Driver
oracle.jdbc.OracleDriver
com.ibm.db2.jcc.DB2Driver

​ 2.定義的實現類必須實現對應介面

​ 3.實現類必須提供無參構造器

3、為什麼說SPI規避了雙親委派機制?

​ 註意,我們前面說了雙親委派機制中,載入器會往上層載入器遞交載入請求,我們已知java.util.ServiceLoader的類載入器為BootStrap載入器。此載入器已經是最頂層,無更加上層的載入器。而按照載入器職責的約定,ServiceLoader所屬類載入器的職責是載入jdk核心類,其是無法載入到用戶的類。例如下圖:

​ 現在的問題是:既然ServiceLoader的類載入器是最頂層的,其載入職責不負責我們自己的類,那麼它是如何載入到類似JDBC這種實現類的呢?

附:ServiceLoader的類載入器是BootStrap類載入器,在程式中是無法獲取到該類的類載入器的。

4、SPI是如何規避雙親委派機制的?

​ 要搞清楚這個問題的原因,得先確認我們使用SPI的入口:

ServiceLoader<Xxxx> serviceLoader = ServiceLoader.load(Xxxx.class);

​ 進入該方法,尋找其實現的方式:

java.util.ServiceLoader#load(java.lang.Class)

​ 註意此處獲取了當前線程的類載入器,而線上程中調用該類方法的是我們用戶自己。那麼這裡就理解為獲取到了用戶的類載入器。

​ 再往該方法中查找,找到該段代碼:

java.util.ServiceLoader#ServiceLoader

​ 註意該段代碼中,cl為上一步獲取到的類載入器,如果發現類載入器不存在,會再次獲取系統預設載入器,這個系統預設載入器在常規情況下是用於載入啟動類的載入器(jdk註釋中解釋),而啟動類則是我們用戶自己定義的類,這裡毋庸置疑也會是應用類載入器。

​ 從上面的代碼中我們總結出來,ServiceLoader獲取了我們的應用類載入器,至此load方法入口基本上沒有其他內容可以細看。

​ 為減輕文章閱讀壓力,直接跳轉到該方法

java.util.ServiceLoader.LazyIterator#nextService

image

​ 註意這裡的loader是我們前面獲取到的應用類載入器,這個方法中是獲取到了具體需要實例化的實現類,即將對其進行實例化, 在這之前需要先獲取到Class,這裡使用Class.forName(class, false, ClassLoader)方法,這個方法的含義是使用指定的類載入器去載入指定的類。既然這裡的類載入器是應用類載入器,那麼類載入順序自然就又回到了應用類載入器-->擴展類載入器-->BootStrap類載入器-->擴展類載入器-->應用類載入器,能載入到我們想要的類也就不奇怪了。

​ 看到這裡也就明白了為什麼使用SPI仍然能正常載入類了。

​ SPI的載入機制看起來雖然方面,但仍然有缺點:

1. 無法實現動態載入、卸載的效果,只有最簡單的載入三方類的實現。
1. 由於實現原因,實現類必須提供無參構造器,局限性和擴展性很低

​ 綜合來說,SPI簡單但局限性大,項目中能接受這些缺點就可以放心使用,如接受不了則可以模擬SPI機制自行實現一套載入機制,自己實現起來擴展性和局限性肯定是原生SPI不能比的。

​ 本次內容結束,如發現內容錯誤請留言,會儘快改正。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # 核心原理 長鏈接轉為短鏈接的核心原理是: 將短鏈接與原始長鏈接做一個映射,訪問短鏈接的時候,通過重定向的方式轉到長鏈接。 # 應用場景 比如分享功能,查看分享信息的原始鏈接通常是很長的,直接發給用戶,體驗不是很好,這時候就可以將其映射為一個短鏈接再發給用戶。 又比如我們熟知的百度網盤分享文件,雖 ...
  • ##一、定義 **講一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式是一種創建型模式。** ##二、描述 **包含以下四個角色:** ![](https://img2023.cnblogs.com/blog/1780813/202305/1780813-202305 ...
  • 你想成為一名架構師,對嗎?別對我撒謊,我知道你想成為架構師。即使你不想,你還是想成為一名更好的開發者。否則,你就不會花時間閱讀這篇文章。 這種態度值得贊賞。畢竟,我們都希望在自己所從事的領域變得更好,即使不能稱為最好。我在這裡就是為了幫助你實現這一目標。 那麼,你如何成為一名架構師呢?當然是通過學習 ...
  • #### 本文為[李你幹嘛](https://www.cnblogs.com/liniganma)原創,轉載請註明出處:[Pybind11綁定C++抽象類(DLL介面)](https://www.cnblogs.com/liniganma/p/17666063.html) # 摘要 假設我們將DLL ...
  • 數據類型是編程中的重要概念。數據類型指定了變數值的大小和類型。 Go是靜態類型的,這意味著一旦變數類型被定義,它只能存儲該類型的數據。 Go有三種基本數據類型: - bool:表示布爾值,要麼是true,要麼是false。 - 數值型:表示整數類型、浮點數值和複數類型。 - string:表示字元串 ...
  • ### Java 8 的改進 - 速度更快 - 代碼更少(**Lambda表達式**) - 引入強大的**Stream API** - 便於並行 - 最大化減少空指針異常(**Optional**) - **Nashorn**引擎,允許在JVM上運行**js**應用 - **並行流**就是把一個內容 ...
  • 概述 Redis底層有六種數據類型包括:簡單動態字元串、雙向鏈表、壓縮列表、哈希表、跳錶和整數數組。這六種數據結構五大數據類型關係如下: String:簡單動態字元串 List:雙向鏈表、壓縮列表 Hash:壓縮列表、哈希表 Sorted Set:壓縮列表、跳錶 Set:哈希表、整數數組 數據類型和 ...
  • 背景: 根據以下簡單的代碼示例,我們將從源碼的角度分析其中的關鍵載入執行步驟,對pytest整體流程架構有個初步學習。 代碼示例: import pytest def test_add(): assert 1 + 1 == 2 def test_sub(): assert 2 - 1 == 1 通過 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...