SPI и API

Java
  • суг команда
  • Автор: Красавчик

SPI и API

SPI чем-то похож на хорошо известный API по названию.SPI называется интерфейсом поставщика услуг, а API называется интерфейсом прикладной программы.Разницу между ними можно приблизительно сравнить таким образом. Допустим, есть клиентская сторона и сервисная сторона, стыкующиеся друг с другом через согласованный интерфейс.

  1. Когда сервисная сторона раскрывает свой бизнес для клиентской стороны, она предоставляет сервисы API.
  2. Клиент реализует интерфейс, предоставляемый сервером, а затем позволяет серверу вызывать себя, предоставляя услуги SPI.

Наиболее распространенная служба SPI, которую мы обычно используем, — это JDBC. Благодаря унифицированной спецификации JDBC клиенты могут самостоятельно реализовывать различные источники данных. Только представьте, если разработчик захочет переключить источник данных с Mysql на Oracle, если не используется JDBC, процесс переключения потребует огромных трудозатрат.

Как решить вышеописанную проблему переключения источника данных, здесь нужно поговорить о принципе инверсии зависимостей.

  1. Модули высокого уровня не должны зависеть от модулей низкого уровня, оба должны зависеть от абстракций.
  2. Абстракция не должна зависеть от деталей
  3. Детали должны опираться на абстракции

JDBC-подключение к Mysql

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(
              "jdbc:mysql://localhost:3306/test", "root", "123456");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from Users");

Ниже представлена ​​упрощенная версия программы JDBC. Программа управления драйверами отвечает за загрузку каждой службы SPI и использует карту для сохранения всех загруженных драйверов, а ключом является пользовательское имя службы SPI. При вызове соединения, если префикс в URL-адресе является именем драйвера, соединение создается с использованием этого драйвера.

/**
 * 驱动管理,负责加载各客户方提供的数据源服务/
 */
public class MyDriverManager {
   /**
     * 所有注册的数据源连接服务/
    */
private static final Map<String, MyDriver> registerDriver = new HashMap<String, MyDriver>();

    public static void registerDriver(String name, MyDriver driver) {
        registerDriver.put(name, driver);
    }

    public static MyConnection getConnection(String url) {
        for (String key : registerDriver.keySet()) {
            if (url.startsWith(key)) {
                return registerDriver.get(key).getConnection(url);
            }
        }
        throw new RuntimeException("no such provider");
    }
}

Определить интерфейс драйвера

public interface MyDriver {
		/**
		 * 获取连接
		 */
		MyConnection getConnection(String url);
}

Программа драйвера, реализованная на стороне клиента, выполняет службу регистрации в блоке статического кода и регистрирует драйвер в программе управления драйверами.

public class MysqlDriver implements MyDriver {

    static {
        MyDriverManager.registerDriver(“mysql”, new MysqlDriver());
    }

    public MyConnection getConnection(String url) {
        System.out.println(“connect to mysql: url = “ + url);
        return new MysqlConnection();
    }
}

В фактическом выполнении используйте Class.Forname, чтобы сначала загрузить драйвер, в противном случае статический код код не будет выполнен, и драйвер не может быть загружен в программу управления драйверами.

public class Main {

    public static void main(String[] args) throws ClassNotFoundException {
        		 Class.forName(“com.github.yaolang.chapter01.spi1.MysqlDriver”);
        MyConnection myConnection = MyDriverManager.getConnection(“mysql://localhost:8080”);
        System.out.println(myConnection);
    }
}

Ниже приведен вывод

connect to mysql: url = mysql://localhost:8080
com.github.yaolang.chapter01.spi1.MysqlConnection@60e53b93