SPI (Service Provider Interface) 是 Java 內置的服務發現機制。核心思想:面向接口編程,實現類由服務提供者在運行時動態指定,而非在代碼中硬編碼。這實現了模塊裝配的控制反轉 (IoC),對插件化、框架擴展至關重要。
META-INF/services/ 目錄下創建以接口全限定名命名的文件java.util.ServiceLoader 載入並實例化服務掃描 META-INF/services/org.apache.commons.logging.LogFactory 獲取日志工廠實現,實現日志門面與具體實現(Log4j、JUL 等)解耦。
驅動提供者在 META-INF/services/java.sql.Driver 指定實現類,應用無需 Class.forName() 即可自動發現驅動。
package my.xyz.spi;
import java.util.List;
public interface Search {
List search(String keyword);
}
package com.A.spi.impl;
public class FileSearch implements Search { ... }
JAR 中 META-INF/services/my.xyz.spi.Search 內容:
com.A.spi.impl.FileSearch
package com.B.spi.impl;
public class DatabaseSearch implements Search { ... }
JAR 中 META-INF/services/my.xyz.spi.Search 內容:
com.B.spi.impl.DatabaseSearch
package com.xyz.factory;
import java.util.Iterator;
import java.util.ServiceLoader;
import my.xyz.spi.Search;
public class SearchFactory {
private SearchFactory() {}
public static Search newSearch() {
ServiceLoader<Search> loader = ServiceLoader.load(Search.class);
Iterator<Search> it = loader.iterator();
return it.hasNext() ? it.next() : null;
}
}
Search search = SearchFactory.newSearch();
search.search("java spi test");
iterator() 時掃描類路徑下所有 META-INF/services/<interface> 文件# 註釋ServiceLoader 按發現順序返回,如需優先級需自行排序module-info.java 聲明 uses 與 providesJava SPI 通過約定優於配置實現服務動態發現,是構建可擴展框架的基石。理解其原理有助於設計靈活的插件架構、框架擴展點及第三方庫集成。