原始碼|什麼是服務提供者框架?舉例?

monkeysayhi發表於2019-01-26

服務提供者框架中有四個重要的元件:

  • 服務介面(Service Interface):由服務提供者實現,用來抽象服務提供者提供的服務。
  • 提供者註冊API(Provider Registration API):系統用來註冊實現,讓客戶端訪問它們的。
  • 服務訪問API(Service Access API):客戶端用來獲取服務的例項。
  • 服務提供者介面(Service Provider Interface):可選,由服務提供者實現,用來抽象服務提供者。

JDBC的實現就是一個服務者提供框架應用的典型例子。

JDBC與服務者提供框架

JDBC中的各角色

JDBC的實現中包含有服務提供者介面,具體如下:

  • 服務介面:Connection
  • 服務提供者介面:Driver
  • 提供者註冊API:DriverManager.registerDriver()方法
  • 服務訪問API:DriverManager.getConnection()方法

具體實現

服務介面:Connection

Connection即為資料庫連線服務,沒什麼特殊的,注意介面的多繼承:

public interface Connection  extends Wrapper, AutoCloseable {
…
}複製程式碼

服務提供者介面:Driver

Driver生成Connection服務:

public interface Driver {
…
    Connection connect(String url, java.util.Properties info)
        throws SQLException;
…
}複製程式碼

記住Driver#connect()方法,後面還會見到。

提供者註冊API:DriverManager.registerDriver()方法

服務的提供者實現Driver類,通過DriverManager.registerDriver()將服務提供者的例項註冊到DriverManager中:

public class DriverManager {
…
    public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {

        registerDriver(driver, null);
    }
…
    public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);

    }
…
}複製程式碼

具體的註冊行為由服務提供者發起。MySQL的Driver實現com.mysql.jdbc.Driver為例:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
…
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can`t register driver!");
        }
    }
…
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
…
}複製程式碼

可知,在第一次載入com.mysql.jdbc.Driver時,com.mysql.jdbc.Driver會利用靜態程式碼塊呼叫提供者註冊API DriverManager.registerDriver()。

服務訪問API:DriverManager.getConnection()方法

註冊服務提供者的例項後,服務提供者就能夠通過框架提供服務。具體來說,可通過靜態工廠方法DriverManager.getConnection()提供Connection服務,底層是通過Driver介面的實現類實現的:

public class DriverManager {
…
    public static Connection getConnection(String url)
        throws SQLException {

        java.util.Properties info = new java.util.Properties();
        return (getConnection(url, info, Reflection.getCallerClass()));
    }
…
    //  Worker method called by the public getConnection() methods.
    private static Connection getConnection(
…
        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!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }
…
    }
…
}複製程式碼

注意這裡的命名方式getConnection,目前的實現中,每次返回的是新的Connection例項,感覺叫做newConnection更恰當。不知道為什麼這樣命名。

這裡的邏輯很簡單,遍歷所有已註冊的Driver實現類,選擇第一個可用的Driver建立Connection。還記得Driver#connect()方法嗎?aDriver.driver.connect一句中,由底層Driver完成Connection的建立

done


本文連結:原始碼|什麼是服務提供者框架?舉例?
作者:猴子007
出處:monkeysayhi.github.io
本文基於 知識共享署名-相同方式共享 4.0 國際許可協議釋出,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名及連結。

相關文章