¿Cuál es la diferencia entre la interfaz de proveedor de servicios (SPI) y la interfaz de programación de aplicaciones (API) ?
Más específicamente, para las bibliotecas de Java, ¿qué las convierte en una API y / o SPI?
¿Cuál es la diferencia entre la interfaz de proveedor de servicios (SPI) y la interfaz de programación de aplicaciones (API) ?
Más específicamente, para las bibliotecas de Java, ¿qué las convierte en una API y / o SPI?
Respuestas:
Dicho de otra manera, la API le dice lo que una clase / método específico hace por usted, y el SPI le dice qué debe hacer para cumplir.
Por lo general, API y SPI están separados. Por ejemplo, en JDBC la Driver
clase es parte del SPI: si simplemente desea usar JDBC, no necesita usarlo directamente, pero todos los que implementen un controlador JDBC deben implementar esa clase.
A veces se superponen, sin embargo. La Connection
interfaz es a la vez SPI y API: se usa de forma rutinaria cuando se usa un controlador JDBC y el desarrollador del controlador JDBC debe implementarla.
@SomeAnnotation
a mi clase para que algún marco lo recoja, ¿ SomeAnnotation.class
se consideraría esta clase de anotación parte del SPI, aunque técnicamente no la extienda o implemente?
De Java efectivo, 2da edición :
Un marco de proveedor de servicios es un sistema en el que múltiples proveedores de servicios implementan un servicio, y el sistema pone las implementaciones a disposición de sus clientes, desacoplándolos de las implementaciones.
Hay tres componentes esenciales de un marco de proveedor de servicios: una interfaz de servicio, que los proveedores implementan; una API de registro de proveedores, que el sistema usa para registrar implementaciones, que les da acceso a los clientes; y una API de acceso al servicio, que los clientes usan para obtener una instancia del servicio. La API de acceso al servicio generalmente permite, pero no requiere, que el cliente especifique algunos criterios para elegir un proveedor. En ausencia de tal especificación, la API devuelve una instancia de una implementación predeterminada. La API de acceso al servicio es la "fábrica estática flexible" que forma la base del marco del proveedor de servicios.
Un cuarto componente opcional de un marco de proveedor de servicios es una interfaz de proveedor de servicios, que los proveedores implementan para crear instancias de su implementación de servicios. En ausencia de una interfaz de proveedor de servicios, las implementaciones se registran por nombre de clase y se instancian de forma reflexiva (Elemento 53). En el caso de JDBC, Connection desempeña el papel de la interfaz de servicio, DriverManager.registerDriver es la API de registro del proveedor, DriverManager.getConnection es la API de acceso al servicio y Driver es la interfaz del proveedor de servicios.
Existen numerosas variantes del patrón de marco del proveedor de servicios. Por ejemplo, la API de acceso al servicio puede devolver una interfaz de servicio más rica que la requerida por el proveedor, utilizando el patrón Adaptador [Gamma95, p. 139]. Aquí hay una implementación simple con una interfaz de proveedor de servicios y un proveedor predeterminado:
// 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();
}
}
La diferencia entre API y SPI se produce cuando una API además proporciona algunas implementaciones concretas. En ese caso, el proveedor de servicios tiene que implementar algunas API (llamadas SPI)
Un ejemplo es JNDI:
JNDI proporciona interfaces y algunas clases para la búsqueda de contexto. La forma predeterminada de buscar un contexto se proporciona en IntialContext. Esta clase internamente usará interfaces SPI (usando NamingManager) para implementaciones específicas del proveedor.
Vea la arquitectura JNDI a continuación para una mejor comprensión.
API significa interfaz de programación de aplicaciones, donde API es un medio para acceder a un servicio / función proporcionado por algún tipo de software o plataforma.
SPI significa Interfaz de proveedor de servicios, donde SPI es una forma de inyectar, extender o alterar el comportamiento del software o una plataforma.
La API normalmente es el objetivo para que los clientes accedan a un servicio y tiene las siguientes propiedades:
-> API es una forma programática de acceder a un servicio para lograr un determinado comportamiento o resultado
-> Desde el punto de vista de la evolución de la API, la adición no es un problema para los clientes
-> Pero las API, una vez utilizadas por los clientes, no pueden (y no deben) ser alteradas / eliminadas a menos que haya una comunicación adecuada, ya que es una degradación completa de las expectativas del cliente
SPI por otro lado está dirigido a proveedores y tiene las siguientes propiedades:
-> SPI es una forma de extender / alterar el comportamiento de un software o una plataforma (programable vs. programático)
-> La evolución de SPI es diferente de la evolución de API, en la eliminación de SPI no es un problema
-> La adición de interfaces SPI causará problemas y puede romper las implementaciones existentes
Para más explicaciones, haga clic aquí: Interfaz de proveedor de servicios
Preguntas frecuentes de NetBeans: ¿Qué es un SPI? ¿Cómo es diferente de una API?
API es un término general, un acrónimo de interfaz de programación de aplicaciones, significa algo (en Java, generalmente algunas clases de Java) que expone una pieza de software, lo que permite que otro software se comunique con ella.
SPI significa interfaz de proveedor de servicios. Es un subconjunto de todas las cosas que pueden ser específicas de la API para situaciones en las que una biblioteca proporciona clases a las que llama la aplicación (o la biblioteca de la API) y que normalmente cambian las cosas que la aplicación puede hacer.
El ejemplo clásico es JavaMail. Su API tiene dos lados:
- El lado de la API, al que puede llamar si está escribiendo un cliente de correo o desea leer un buzón
- El lado SPI si está proporcionando un controlador de protocolo de cable para permitir que JavaMail hable con un nuevo tipo de servidor, como un servidor de noticias o IMAP
Los usuarios de la API rara vez necesitan ver o hablar con las clases SPI, y viceversa.
En NetBeans, cuando ve el término SPI, generalmente se trata de clases que un módulo puede inyectar en tiempo de ejecución que permiten a NetBeans hacer cosas nuevas. Por ejemplo, hay un SPI general para implementar sistemas de control de versiones. Los diferentes módulos proporcionan implementaciones de ese SPI para CVS, Subversion, Mercurial y otros sistemas de control de revisión. Sin embargo, el código que trata con archivos (en el lado de la API) no necesita preocuparse si hay un sistema de control de versiones o lo que es.
Hay un aspecto que no parece destacarse mucho, pero es muy importante para entender el razonamiento detrás de la existencia de la división API / SPI.
La división API / SPI solo se requiere cuando se espera que la plataforma evolucione. Si escribe una API y "sabe" que no requerirá ninguna mejora futura, no hay razones reales para dividir su código en las dos partes (además de hacer un diseño de objeto limpio).
Pero este casi nunca es el caso y las personas necesitan tener la libertad de evolucionar la API junto con los requisitos futuros, de una manera compatible con versiones anteriores.
Tenga en cuenta que todo lo anterior supone que está construyendo una plataforma que otras personas usan y / o extienden y no su propia API donde tiene todo el código del cliente bajo control y, por lo tanto, puede refactorizar como lo necesite.
Vamos a mostrarlo en uno de los objetos Java Collection
y conocidos Collections
.
API: Collections
es un conjunto de métodos estáticos de utilidad. A menudo, las clases que representan el objeto API se definen final
porque asegura (en el momento de la compilación) que ningún cliente puede "implementar" ese objeto y puede depender de "llamar" a sus métodos estáticos, por ejemplo
Collections.emptySet();
Como todos los clientes están "llamando" pero no "implementando" , los autores de JDK son libres de agregar nuevos métodos al Collections
objeto en la versión futura de JDK. Pueden estar seguros de que no puede afectar a ningún cliente, incluso si probablemente haya millones de usos.
SPI: Collection
es una interfaz que implica que cualquiera puede implementar su propia versión. Por lo tanto, los autores de JDK no pueden agregar nuevos métodos, ya que rompería a todos los clientes que escribieron su propia Collection
implementación (*).
Por lo general, cuando se requiere agregar un método adicional, se debe crear una nueva interfaz, por ejemplo, Collection2
que amplíe la anterior. El cliente SPI puede decidir si migrar a la nueva versión de SPI e implementar su método adicional o si se queda con la anterior.
Puede que ya hayas visto el punto. Si combina ambas piezas juntas en una sola clase, su API se bloquea de cualquier adición. Esa es también la razón por la cual las buenas API y Frameworks de Java no se exponen, abstract class
ya que bloquearían su evolución futura con respecto a la compatibilidad con versiones anteriores.
Si algo aún no está claro, recomiendo consultar esta página que explica lo anterior con más detalle.
(*) Tenga en cuenta que esto es cierto solo hasta Java 1.8, que introduce el concepto de default
métodos definidos en una interfaz.
Supongo que un SPI se inserta en un sistema más grande implementando ciertas características de una API y luego registrándose como disponible a través de mecanismos de búsqueda de servicios. El código de la aplicación del usuario final utiliza una API directamente, pero puede integrar componentes SPI. Es la diferencia entre encapsulación y uso directo.
La interfaz del proveedor de servicios es la interfaz de servicio que todos los proveedores deben implementar. Si ninguna de las implementaciones de proveedores existentes funciona para usted, debe escribir su propio proveedor de servicios (implementando la interfaz de servicio) y registrarse en algún lugar (vea la publicación útil de Roman).
Si está reutilizando la implementación del proveedor existente de la interfaz de servicio, básicamente está utilizando la API de ese proveedor en particular, que incluye todos los métodos de la interfaz de servicio más algunos métodos públicos propios. Si está utilizando métodos de API de proveedor fuera del SPI, está utilizando funciones específicas del proveedor.
En el mundo de Java, las diferentes tecnologías están destinadas a ser modulares y "conectables" en un servidor de aplicaciones. Entonces hay una diferencia entre
Dos ejemplos de tales tecnologías son JTA (el administrador de transacciones) y JCA (adaptador para JMS o base de datos). Pero hay otros.
El implementador de dicha tecnología enchufable debe implementar el SPI para que pueda enchufarse en la aplicación. servidor y proporcionar una API para ser utilizada por la aplicación de usuario final. Un ejemplo de JCA es la interfaz ManagedConnection que forma parte del SPI y la conexión que forma parte de la API del usuario final.