В чем разница между интерфейсом поставщика услуг (SPI) и интерфейсом прикладного программирования (API) ?
Более конкретно, для библиотек Java, что делает их API и / или SPI?
В чем разница между интерфейсом поставщика услуг (SPI) и интерфейсом прикладного программирования (API) ?
Более конкретно, для библиотек Java, что делает их API и / или SPI?
Ответы:
Иными словами, API сообщает вам, что для вас делает определенный класс / метод, а SPI говорит вам, что вы должны сделать, чтобы соответствовать.
Обычно API и SPI являются отдельными. Например, в JDBC класс является частью SPI: Если вы просто хотите использовать JDBC, вам не нужно использовать его непосредственно, но каждый , кто реализует драйвер JDBC должен реализовывать этот класс.Driver
Однако иногда они перекрываются. Интерфейс является как SPI и API: Вы можете использовать его регулярно , когда вы используете драйвер JDBC , и он должен быть реализован разработчиком драйвера JDBC.Connection
@SomeAnnotation
в свой класс, чтобы его подобрал какой-то фреймворк, будет ли этот класс аннотаций SomeAnnotation.class
считаться частью SPI, даже если я технически не расширяю или не реализую его?
Из эффективной Java, 2-е издание :
Инфраструктура поставщика услуг - это система, в которой несколько поставщиков услуг внедряют услугу, и система делает реализации доступными для своих клиентов, отделяя их от реализаций.
Существуют три основных компонента структуры поставщика услуг: интерфейс службы, который реализуют поставщики; API регистрации провайдера, который система использует для регистрации реализаций, предоставляя клиентам доступ к ним; и API доступа к сервису, который клиенты используют для получения экземпляра сервиса. API доступа к сервису обычно позволяет, но не требует от клиента указывать некоторые критерии для выбора поставщика. В отсутствие такой спецификации API возвращает экземпляр реализации по умолчанию. API доступа к сервису - это «гибкая статическая фабрика», которая составляет основу инфраструктуры поставщика услуг.
Необязательным четвертым компонентом структуры поставщика услуг является интерфейс поставщика услуг, который поставщики реализуют для создания экземпляров реализации своих услуг. В отсутствие интерфейса поставщика услуг реализации регистрируются по имени класса и создаются рефлексивно (Элемент 53). В случае JDBC Connection играет роль интерфейса службы, DriverManager.registerDriver - это API регистрации поставщика, DriverManager.getConnection - это API доступа к службе, а Driver - интерфейс поставщика службы.
Существует множество вариантов шаблона структуры поставщика услуг. Например, API доступа к сервису может вернуть более богатый интерфейс сервиса, чем тот, который требуется от провайдера, используя шаблон адаптера [Gamma95, p. 139]. Вот простая реализация с интерфейсом поставщика услуг и поставщиком по умолчанию:
// Service provider framework sketch
// Service interface
public interface Service {
... // Service-specific methods go here
}
// Service provider interface
public interface Provider {
Service newService();
}
// Noninstantiable class for service registration and access
public class Services {
private Services() { } // Prevents instantiation (Item 4)
// Maps service names to services
private static final Map<String, Provider> providers =
new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>";
// Provider registration API
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
public static void registerProvider(String name, Provider p){
providers.put(name, p);
}
// Service access API
public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider p = providers.get(name);
if (p == null)
throw new IllegalArgumentException(
"No provider registered with name: " + name);
return p.newService();
}
}
Разница между API и SPI возникает, когда API дополнительно предоставляет некоторые конкретные реализации. В этом случае поставщик услуг должен реализовать несколько API (называемых SPI).
Примером является JNDI:
JNDI предоставляет интерфейсы и некоторые классы для поиска по контексту. Способ поиска контекста по умолчанию предоставляется в IntialContext. Этот класс внутренне будет использовать интерфейсы SPI (используя NamingManager) для конкретных реализаций провайдера.
Посмотрите Архитектуру JNDI ниже для лучшего понимания.
API означает интерфейс прикладного программирования, где API - это средство доступа к услуге / функции, предоставляемой каким-либо программным обеспечением или платформой.
SPI расшифровывается как Service Provider Interface, где SPI - это способ внедрить, расширить или изменить поведение программного обеспечения или платформы.
API обычно предназначен для доступа клиентов к сервису и имеет следующие свойства:
-> API - это программный способ доступа к сервису для достижения определенного поведения или вывода
-> С точки зрения развития API, добавление не является проблемой для клиентов
-> Но API, когда-то использованный клиентами, не может (и не должен) изменяться / удаляться, если нет соответствующей связи, так как это полностью ухудшает ожидания клиента
SPI, с другой стороны, предназначен для поставщиков и имеет следующие свойства:
-> SPI - это способ расширить / изменить поведение программного обеспечения или платформы (программируемый или программный)
-> Развитие SPI отличается от развития API, удаление SPI не является проблемой
-> Добавление интерфейсов SPI вызовет проблемы и может нарушить существующие реализации
Для получения более подробной информации нажмите здесь: Интерфейс поставщика услуг
Часто задаваемые вопросы по NetBeans: что такое SPI? Чем он отличается от API?
API - это общий термин - аббревиатура для интерфейса прикладного программирования - он означает что-то (в Java, обычно в некоторых классах Java) часть программного обеспечения, которое позволяет другим программам взаимодействовать с ним.
SPI означает интерфейс поставщика услуг. Это подмножество всех вещей, которые могут быть специфичными для API в ситуациях, когда библиотека предоставляет классы, которые вызываются приложением (или библиотекой API), и которые обычно изменяют возможности приложения.
Классическим примером является JavaMail. Его API имеет две стороны:
- Сторона API - которую вы вызываете, если пишете почтовый клиент или хотите прочитать почтовый ящик
- Сторона SPI, если вы предоставляете обработчик проводного протокола, позволяющий JavaMail взаимодействовать с сервером нового типа, таким как сервер новостей или IMAP
Пользователям API редко нужно видеть классы SPI или разговаривать с ними, и наоборот.
В NetBeans, когда вы видите термин SPI, обычно говорят о классах, которые модуль может внедрить во время выполнения, которые позволяют NetBeans делать новые вещи. Например, существует общий SPI для реализации систем контроля версий. Различные модули предоставляют реализации этого SPI для CVS, Subversion, Mercurial и других систем контроля версий. Однако коду, который имеет дело с файлами (сторона API), не нужно заботиться о том, существует ли система контроля версий или какая она есть.
Есть один аспект, который, кажется, не особо выделяется, но очень важен для понимания причин существования разделения API / SPI.
Разделение API / SPI требуется только тогда, когда ожидается развитие платформы. Если вы пишете API и «знаете», он никогда не потребует каких-либо улучшений в будущем, нет никаких реальных причин для разделения вашего кода на две части (кроме создания чистого объектного дизайна).
Но это почти никогда не происходит, и людям нужно иметь свободу для развития API вместе с будущими требованиями - обратно совместимым способом.
Обратите внимание, что все вышеперечисленное предполагает, что вы создаете платформу, которую другие люди используют и / или расширяют, а не свой собственный API, где у вас есть весь клиентский код под контролем, и, таким образом, вы можете реорганизовать его так, как вам нужно.
Давайте покажем это на одном из известных объектов Java Collection
и Collections
.
API: Collections
набор служебных статических методов. Часто классы, представляющие объект API, определяются так, final
как это гарантирует (во время компиляции), что ни один клиент не может «реализовать» этот объект, и они могут зависеть от «вызова» его статических методов, например
Collections.emptySet();
Поскольку все клиенты «вызывают», но не «внедряют» , авторы JDK могут добавлять новые методы в Collections
объект в будущей версии JDK. Они могут быть уверены, что это не сломает ни одного клиента, даже если его использование исчисляется миллионами.
SPI: Collection
это интерфейс, который подразумевает, что любой может реализовать свою собственную версию. Таким образом, авторы JDK не могут добавлять в него новые методы, так как это нарушит работу всех клиентов, написавших свою собственную Collection
реализацию (*).
Как правило, когда требуется добавить дополнительный метод, необходимо создать новый интерфейс, например, Collection2
который расширяет прежний. Затем клиент SPI может решить, следует ли перейти на новую версию SPI и реализовать его дополнительный метод, или же придерживаться более старого.
Возможно, вы уже видели смысл. Если вы объедините обе части в один класс, ваш API заблокирован от любых дополнений. Это также причина, по которой хорошие Java API и Frameworks не раскрываются, abstract class
поскольку они блокируют их дальнейшее развитие в отношении обратной совместимости.
Если что-то все еще неясно, я рекомендую проверить эту страницу, которая объясняет выше более подробно.
(*) Обратите внимание, что это верно только до Java 1.8, который вводит понятие default
методов, определенных в интерфейсе.
Я полагаю, что слоты SPI превращаются в более крупные системы путем реализации определенных функций API, а затем регистрируются как доступные через механизмы поиска служб. API используется кодом приложения конечного пользователя напрямую, но может интегрировать компоненты SPI. Это разница между инкапсуляцией и прямым использованием.
Интерфейс поставщика услуг - это интерфейс службы, который должны быть реализованы всеми поставщиками. Если ни одна из существующих реализаций провайдера не работает для вас, вам нужно написать собственного провайдера услуг (реализующий интерфейс сервиса) и где-нибудь зарегистрироваться (см. Полезный пост Романа).
Если вы повторно используете реализацию сервисного интерфейса существующего провайдера, вы в основном используете API этого конкретного провайдера, который включает в себя все методы интерфейса сервиса и несколько собственных открытых методов. Если вы используете методы API провайдера вне SPI, вы используете специальные функции провайдера.
В мире Java различные технологии должны быть модульными и «подключаемыми» к серверу приложений. Тогда есть разница между
Двумя примерами таких технологий являются JTA (менеджер транзакций) и JCA (адаптер для JMS или базы данных). Но есть и другие.
Разработчик такой подключаемой технологии должен затем реализовать SPI для подключения в приложении. сервер и предоставить API для использования приложением конечного пользователя. Примером из JCA является интерфейс ManagedConnection, который является частью SPI, и Connection, который является частью API конечного пользователя.