JDK之SPI機制
個人理解
- SPI就是一種約定機制,通常情況下, 我們服務都會有一個介面和一個實作類,當服務提供者提供某個服務時,需要在/META-INF/services/目錄下創建以介面路徑命名的文
- 在這個檔案中, 指定我們實作的服務com.demo.impl.UserServiceImpl;
package com.tuling;
public interface Product {
void use();
}
public class Phone implements Product{
@Override
public void use() {
System.out.println("call");
}
}
package com.tuling;
public class Food implements Product{
@Override
public void use() {
System.out.println("eat");
}
}
在/META-INF/services/創建一個com.demo.UserService檔案
com.tuling.Phone
com.tuling.Food
JDK 的SPI呼叫機制
ServiceLoader<Product> productServiceLoader = ServiceLoader.load(Product.class);
Iterator<Product> iterator = productServiceLoader.iterator();
while (iterator.hasNext()){
Product product = iterator.next();
product.use();
}
運行結果:
call
eat
- ServiceLoader是JDK自帶實作的SPI掃描類, 傳入介面類Class資訊, 然后JDK會根據介面的路徑資訊去掃描/META-INF/services/com.tuling.Product檔案
- 然后將檔案里面的內容一行一行全部讀取出來,使用反射技術,將指定的實作類Phone,Food通過反射實體化, 放入某種資料結構容器中;
通過上面的簡單例子, 差不多就可以理解SPI是個什么東西,
SPI機制的作用
步入正題, 那么JDK提供SPI機制的作用是什么呢?
- 解耦
- 與實作組件化,模塊化;
- 可以提供一套介面規范, 每個依賴包提供介面實作類,然后在/WEB-INF/services下的以介面路徑命令的檔案里, 指定包的實作類,專案啟動的時候, 就會去掃描/WEB-INF/services下的檔案,一起使用;
SPI機制常見舉例
舉個例子: 我們開發使用的DB操作, 一般會有Mysql, Oracle等,那么JDBC中, 有一個DriverManger類, 用來獲取資料庫連接;
JDBC提供了一個java.sql.Driver 介面,當我們使用不同的資料庫時,各大廠商(如Mysql、Oracle)會根據一個統一的規范(java.sql.Driver)開發各自的驅動實作邏輯,客戶端使用jdbc時不需要去改變代碼,mysql依賴包中 /WEB-INF/services/有一個java.sql.Driver檔案, 內容指定了Driver的實作類是com.mysql.jdbc.Driver, oracle依賴包中/WEB-INF/services/也有一個java.sql.Driver,內容指定了Driver的實作類是oracle.jdbc.driver.OracleDriver;
package java.sql;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.CopyOnWriteArrayList;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
public class DriverManager {
@CallerSensitive
public static Connection getConnection(String url,
java.util.Properties info) throws SQLException {
return (getConnection(url, info, Reflection.getCallerClass()));
}
//...
}
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
}
for(DriverInfo aDriver : registeredDrivers) 回圈中的registeredDrivers代表的就是所有的Driver實作類,再根據每個驅動Driver實作類去連接具體的資料庫;
而我們專案中可以一次引入mysql,oracle等多種資料庫, 只需要在Mybatis的組態檔中指定使用哪種資料庫, 進而再獲取連接的時候,創建相關資料庫的連接;
Java SPI機制的特點
優點:
- 插件化
- 模塊化
缺點:
- 不夠靈活;
只可以獲取所有的 規范實作, 做不到只獲取部分規范實作;
專案可能使用10種資料庫,就需要匯入10種資料庫包,我們短時間內只用到了3種 他就會將10種資料庫的規范實作Driver全部掃描進來, 而不能只獲取3種;
總結
Dubbo的SPI擴展機制就是對Java SPI機制的擴展, 使其更加靈活可用;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/427505.html
標籤:其他
上一篇:一篇理清大資料技術發展和要求
