Java-75 深入淺出 RPC Dubbo Java SPI機制詳解:從JDK到Dubbo的插件式擴展

點一下關注吧!!!非常感謝!!持續更新!!!

🚀 AI篇持續更新中!(長期更新)

AI煉丹日志-30-新發布【1T 萬億】參數量大模型!Kimi?K2開源大模型解讀與實踐,持續打造實用AI工具指南!📐🤖

💻 Java篇正式開啟!(300篇)

目前2025年07月16日更新到:
Java-74 深入淺出 RPC Dubbo Admin可視化管理 安裝使用 源碼編譯、Docker啟動
MyBatis 已完結,Spring 已完結,Nginx已完結,Tomcat已完結,分布式服務正在更新!深入淺出助你打牢基礎!

📊 大數據板塊已完成多項干貨更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余項核心組件,覆蓋離線+實時數倉全棧!
大數據-278 Spark MLib - 基礎介紹 機器學習算法 梯度提升樹 GBDT案例 詳解

Java SPI(Service Provider Interface)是一種內置的服務發現機制,結合接口編程、策略模式和配置文件,允許在運行時動態加載實現類。SPI廣泛用于 JDBC、JNDI、日志、XML 解析等場景,核心依賴 ServiceLoader 實現解耦與可插拔擴展。使用時需在 META-INF/services 下配置實現類路徑。Dubbo 基于 SPI 機制實現了自己的擴展體系,支持負載均衡、協議選擇等插件化設計,用戶可自定義實現并通過注解 @SPI 與配置文件指定默認服務,實現靈活的服務擴展與適配。

請添加圖片描述

SPI (Service Provider Interface)

SPI 簡介

SPI(Service Provider Interface)是 Java 開發工具包(JDK)內置的一種服務提供發現機制。它作為一種標準化的服務擴展點發現方式,目前被廣泛應用于各種框架中來實現服務的動態擴展。

SPI 工作機制

SPI 的核心思想是"面向接口編程+策略模式+配置文件"的組合實現。具體工作流程為:

  1. 定義服務接口(如java.sql.Driver
  2. META-INF/services/目錄下創建以接口全限定名命名的文件
  3. 在該文件中寫入具體實現類的全限定名(如com.mysql.jdbc.Driver
  4. 通過ServiceLoader類加載并實例化這些實現類

SPI 的優勢

  1. 解耦性:將服務接口與具體實現分離,調用方只需面向接口編程
  2. 擴展性:新增服務實現無需修改原有代碼,只需添加新的實現類
  3. 動態性:服務實現可以在運行時動態發現和加載
  4. 標準化:作為 JDK 標準機制,提供統一的擴展方式

典型應用場景

  1. JDBC 數據庫驅動加載(java.sql.Driver
  2. JNDI 服務提供者(javax.naming.spi.InitialContextFactory
  3. XML 解析器(javax.xml.parsers.DocumentBuilderFactory
  4. 日志框架(java.util.logging.LogManager
  5. Spring Boot 自動配置機制

示例:JDBC 通過 SPI 加載不同數據庫驅動

// 通過 SPI 自動發現并加載驅動
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, user, password);

SPI 機制實現了"約定優于配置"的原則,是 Java 生態中實現可插拔架構的重要基礎。

JDK中的SPI

在這里插入圖片描述

Java SPI 使用詳解

1. 標準服務接口定義

首先需要定義一個標準服務接口,作為SPI機制的契約。這個接口將被服務提供者實現,被服務調用者使用。

示例:

// 定義支付接口標準
package com.example.spi;public interface PaymentService {/*** 支付方法* @param amount 支付金額* @return 支付結果*/String pay(double amount);/*** 獲取支付方式名稱* @return 支付方式*/String getPaymentMethod();
}

2. 服務提供者實現

2.1 實現接口

服務提供者需要提供該接口的具體實現。例如我們實現一個支付寶支付服務:

package com.example.provider;import com.example.spi.PaymentService;public class AlipayService implements PaymentService {@Overridepublic String pay(double amount) {return "支付寶支付成功,金額:" + amount;}@Overridepublic String getPaymentMethod() {return "Alipay";}
}
2.2 創建配置文件

在資源目錄下創建 META-INF/services 目錄,并添加以接口全限定名命名的文件:

文件路徑:META-INF/services/com.example.spi.PaymentService
文件內容:

com.example.provider.AlipayService
2.3 打包注意事項
  • 實現類必須包含無參構造器
  • 實現類所在的JAR包需要包含META-INF/services目錄
  • 多個實現可以在配置文件中逐行列出

3. 服務調用者使用

3.1 通過ServiceLoader加載

調用者使用ServiceLoader動態加載實現:

import com.example.spi.PaymentService;
import java.util.ServiceLoader;public class PaymentApp {public static void main(String[] args) {ServiceLoader<PaymentService> services = ServiceLoader.load(PaymentService.class);for (PaymentService service : services) {System.out.println("發現支付服務: " + service.getPaymentMethod());System.out.println(service.pay(100.0));}}
}
3.2 類路徑配置

確保:

  1. 接口定義的JAR包在classpath中
  2. 所有實現類的JAR包也在classpath中
  3. 如果使用Maven/Gradle,添加相應的依賴關系

4. 高級用法

4.1 多個實現共存

可以同時提供多個實現,例如再添加一個微信支付:

package com.example.provider;import com.example.spi.PaymentService;public class WechatPayService implements PaymentService {@Overridepublic String pay(double amount) {return "微信支付成功,金額:" + amount;}@Overridepublic String getPaymentMethod() {return "WeChat Pay";}
}

然后在配置文件中添加:

com.example.provider.AlipayService
com.example.provider.WechatPayService
4.2 實際應用場景

SPI機制常用于:

  • 支付網關集成
  • 數據庫驅動加載(如JDBC)
  • 日志框架適配
  • 序列化協議支持
  • 插件化系統開發

5. 注意事項

  1. ServiceLoader不是線程安全的
  2. 實現類必須有無參構造器
  3. 服務加載是延遲初始化的
  4. 每次調用ServiceLoader.load()都會返回新的實例
  5. 可以通過迭代器模式獲取所有實現

Dubbo中的SPI

dubbo 中大量的使用了SPI來作為擴展點,通過實現同一接口的前提下,可以進行定制自己的實現類,比如比較常見的協議,負載均衡,都可以通過 SPI 的方式進行定制化,自己擴展。Dubbo 中已經存在的所有已經實現的擴展點。

在這里插入圖片描述

下圖中是默認的提供的負載均衡的策略:
在這里插入圖片描述

擴展點使用

我們將使用三個項目來演示 Dubbo 中擴展點的使用方式,一個主項目 main,一個服務接口項目 api,一個服務實現項目 impl

API 項目創建

● 導入坐標 dubbo
● 創建接口
● 在接口上使用 SPI

impl 項目創建

● 導入 api 項目的依賴
● 建立實現類,為了表達支持多個實現的目的,這里分別創建兩個實現,分別是:WzkHumanHelloService 和 WzkDogHelloService。
● SPI 進行聲明操作,在 resources 目錄下創建 META-INF/dubbo 目錄,在目錄下創建 “icu.wzk.service.WzkHelloService” 的文件

該文件內容中寫入進行擴展的類:

human=icu.wzk.service.impl.WzkHumanHelloService
dog=icu.wzk.service.impl.WzkDogHelloService

我們可以看到下面的目錄如下:
在這里插入圖片描述
這里我們需要回顧一下之前的內容,之前我們已經定義了 WzkHelloService,我們在之前代碼的基礎上,進行了如下的擴展,這里值得注意的是:默認實現 這里選的是 dog, 也就是:icu.wzk.service.impl.WzkDogHelloService。

PS:SPI指定一個默認實現,屬于一個兜底機制,比如消費者調用的時候,沒有指定服務,那就會走這個默認的服務。

package icu.wzk.service;import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI;@SPI("dog")
public interface WzkHelloService {String sayHello(String name);@AdaptiveString sayHello( URL url);
}

接著我們要在目錄下新建這兩個類出來:
WzkHumanHelloService的內容如下所示:

package icu.wzk.service.impl;import icu.wzk.service.WzkHelloService;
import org.apache.dubbo.common.URL;public class WzkHumanHelloService implements WzkHelloService {@Overridepublic String sayHello(String name) {return "WzkHuman: " + name;}@Overridepublic String sayHello(URL url) {return "WzkHuman URL: " + url;}
}

我們也實現一下 WzkDogHelloService,實現的內容如下:

package icu.wzk.service.impl;import icu.wzk.service.WzkHelloService;
import org.apache.dubbo.common.URL;public class WzkDogHelloService implements WzkHelloService {@Overridepublic String sayHello(String name) {return "WzkDog: " + name;}@Overridepublic String sayHello(URL url) {return "WzkDog URL: " + url;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91662.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【橘子分布式】gRPC(編程篇-上)

一、簡介 我們之前學習了grpc的一些理論知識&#xff0c;現在我們開始正式進入編程環節。 我們的項目結構和之前的thrift結構還是一樣的&#xff0c;一個common,一個client&#xff0c;一個server。只不過在grpc這里common它一般叫做api模塊。還是放置一些公共的實體類&#x…

IOS 18下openURL 失效問題

突然有一天有玩家反饋說應用打開外部連接打不開了&#xff0c;于是查了一下&#xff0c;報錯&#xff1a;BUG IN CLIENT OF UIKIT: The caller of UIApplication.openURL(_:) needs to migrate to the non-deprecated UIApplication.open(_:options:completionHandler:). Force…

前端面試題(React 與 Vue)

目錄 一、React 函數組件 Fiber架構 組件重新渲染 組件通信 為什么不能在if中使用hook useEffect與useLayoutEffect區別 性能優化hooks 受控組件與非受控組件 redux與zustand區別 二、Vue vue2與vue3區別 生命周期 computed與watch區別 v-if與v-show區別 v-mod…

大模型格式

目錄 大模型格式&#xff1a; ollma 可以加載gguf ChatGPT 說&#xff1a; &#x1f50d; 什么是 GGUF&#xff1f; 大模型格式&#xff1a; Ollama 模型格式只能運行已打包成 .gguf 格式的模型&#xff0c;或通過其 Modelfile 方式構建 ModelScope 模型格式大多使用 Hug…

數據結構 棧(1)

1. 棧的概念和結構之前幾篇我們分別講解了順序表和單鏈表的內容&#xff0c;今天我們又來學習一個新的關于數據結構的內容--- 棧 。棧&#xff1a;棧也屬于線性表 , 但它是一種特殊的線性表&#xff0c;其只允許在固定的一端進行插入和刪除元素操作。進行數據插入和刪除操作的一…

【Android代碼】繪本翻頁時通過AI識別,自動通過手機/pad朗讀繪本

核心功能&#xff1a; 打開攝像頭&#xff08;可支持外接攝像頭&#xff09;檢測翻頁&#xff08;后續考慮添加圖像差異算法&#xff09;拍照后用 識圖自動用 TextToSpeech 朗讀文字內容 &#x1f4cc; 說明&#xff1a;使用了 CameraX&#xff08;Android Jetpack&#xff09;…

園區IPv6規劃與部署

?今天我將圍繞“園區IPv6規劃與部署”這一主題&#xff0c;結合行業趨勢、技術難點和實際案例&#xff0c;與大家分享一套可落地的規劃方法論。?在開始前&#xff0c;我想先問大家一個問題&#xff1a;?如果現在讓你給一個新建園區設計網絡&#xff0c;你會優先考慮IPv4還是…

mingw11.2+opencv4.12 cmake contrib編譯

第一次Configure之后&#xff0c;會出現不少錯誤&#xff0c;主要是因為文件沒辦法正常下載引起的,因為之前編譯過vs2022 ,緩存里面有應該下載的文件了&#xff0c;所以這次沒有錯誤&#xff0c;如果你第一次Configure有下載錯誤&#xff0c;可以下載以下的文件飛書 Docs Link:…

免費MCP服務:Excel CSV 轉 JSON MCP by WTSolutions 文檔

簡介 Excel 轉 JSON MCP&#xff08;模型上下文協議&#xff09;提供了一個標準化接口&#xff0c;用于通過模型上下文協議將 Excel 和 CSV 數據轉換為 JSON 格式。此 MCP 實現提供了兩個專門用于數據轉換的工具&#xff1a; excel_to_json_mcp_from_data&#xff1a;轉換制表…

應用集成體系深度解析:從數據互通到流程協同

一、應用集成核心概念框架 #mermaid-svg-0V3XAJsofKi2qCa7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-0V3XAJsofKi2qCa7 .error-icon{fill:#552222;}#mermaid-svg-0V3XAJsofKi2qCa7 .error-text{fill:#552222;s…

深入解析 AWS RDS Proxy

在當今微服務架構與無服務器計算快速發展的背景下&#xff0c;數據庫連接成為許多應用系統的性能瓶頸。傳統RDS實例在處理大量短連接請求時&#xff0c;往往面臨連接資源耗盡、連接建立耗時過高等問題。為了解決這一挑戰&#xff0c;AWS 推出了 RDS Proxy 服務&#xff0c;通過…

深度剖析 TDMQ RabbitMQ 版經典隊列底層存儲機制

導語 RabbitMQ 作為開源消息隊列的標桿產品&#xff0c;憑借靈活的路由機制與高可用設計&#xff0c;支撐著海量業務場景的消息流轉。而經典隊列&#xff08;Classic Queue&#xff09; 作為 RabbitMQ 最基礎、應用最廣泛的隊列類型&#xff0c;其底層存儲機制直接決定了消息處…

Spring AI開發智能客服(Tool calling)

文章目錄前言1 思路分析2 工程結構搭建1_數據庫表2_引入依賴3_基礎代碼3 定義 Tool1_分析查詢條件2_定義Function4 系統提示詞5 配置ChatClient6 編寫Controller7 測試8 Tool calling 底層組件1_ToolCallback2_ToolDefinition3_ToolCallingManager4_ResultConverter5_ToolConte…

設計模式筆記_結構型_適配器模式

1.適配器模式介紹適配器模式是一種結構型設計模式&#xff0c;它允許不兼容的接口協同工作。適配器模式的核心思想是將一個類的接口轉換成客戶期望的另一個接口&#xff0c;使得原本由于接口不兼容而不能一起工作的類可以一起工作。你可以將其想象成一個“轉換插頭”——假設你…

事務隔離:從鎖實現到MVCC實現

文章目錄事務隔離&#xff1a;從鎖實現到MVCC實現事務四大特性事務隔離級別鎖實現概念實現事務隔離MVCC實現當前讀與快照讀實現事務隔離Read View總結事務隔離&#xff1a;從鎖實現到MVCC實現 面試的時候被面試官問到&#xff1a;你這個項目為什么使用了可重復讀而不選擇讀已提…

小架構step系列18:工具

1 概述 在寫代碼的時候&#xff0c;有很多通用的、與業務無關邏輯&#xff0c;這些一般寫成工具類方法。這些工具類方法慢慢地被積累起來&#xff0c;變成了開源包&#xff0c;可以直接使用開源包&#xff0c;而不是自己再花時間來重復造這些輪子。 這些工具類的開源包比較多…

網絡、CentOS 系統、數據庫面試知識點總結

文章目錄Linux CentOS 面試知識點整理速查復習? 一、Linux 高頻面試題? 二、MySQL 高頻面試題? 三、計算機網絡&#xff08;OSI四層模型&#xff09;高頻面試題&#x1f517; 鏈路層&#xff08;Link Layer&#xff09;&#x1f310; 網絡層&#xff08;Internet Layer&…

Vue (Official) v3.0.2 新特性 為非類npm環境引入 globalTypesPath 選項

目錄 前言 報錯信息 原因 解決方案 總結 前言 在早上更新了vscode后&#xff0c;發現自己 uni-app 項目的 .vue文件 的 template 標簽都出現了報錯。定位到了問題是因為 Vue (Official) 插件更新導致的&#xff0c;重裝了插件的上一個小版本&#xff0c;報錯消失&#xff…

程序可能的輸出

#include "csapp.h"int main() {int x 3;if (Fork() ! 0)printf("x%d\n", x);printf("x%d\n", --x);exit(0); }分析&#xff1a;父進程先執行printf("x%d\n", x); 輸出x4。后執行 printf("x%d\n", --x);輸出x3。子進程只執…

2025年UDP應用抗洪指南:從T級清洗到AI免疫,實戰防御UDP洪水攻擊

一次未防護的UDP暴露&#xff0c;可能讓日活百萬的應用瞬間癱瘓&#xff0c;損失超千萬2025年&#xff0c;隨著物聯網僵尸網絡規模指數級增長及AI驅動的自適應攻擊工具泛濫&#xff0c;UDP洪水攻擊峰值已突破8Tbps&#xff0c;單次攻擊成本卻降至50元以下。更致命的是&#xff…