- суг команда
- Автор: Красавчик
SPI и API
SPI чем-то похож на хорошо известный API по названию.SPI называется интерфейсом поставщика услуг, а API называется интерфейсом прикладной программы.Разницу между ними можно приблизительно сравнить таким образом. Допустим, есть клиентская сторона и сервисная сторона, стыкующиеся друг с другом через согласованный интерфейс.
- Когда сервисная сторона раскрывает свой бизнес для клиентской стороны, она предоставляет сервисы API.
- Клиент реализует интерфейс, предоставляемый сервером, а затем позволяет серверу вызывать себя, предоставляя услуги SPI.
Наиболее распространенная служба SPI, которую мы обычно используем, — это JDBC. Благодаря унифицированной спецификации JDBC клиенты могут самостоятельно реализовывать различные источники данных. Только представьте, если разработчик захочет переключить источник данных с Mysql на Oracle, если не используется JDBC, процесс переключения потребует огромных трудозатрат.
Как решить вышеописанную проблему переключения источника данных, здесь нужно поговорить о принципе инверсии зависимостей.
- Модули высокого уровня не должны зависеть от модулей низкого уровня, оба должны зависеть от абстракций.
- Абстракция не должна зависеть от деталей
- Детали должны опираться на абстракции
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