What is the difference between Service Provider Interface (SPI) and Application Programming Interface (API)?
More specifically, for Java libraries, what makes them an API and/or SPI?
What is the difference between Service Provider Interface (SPI) and Application Programming Interface (API)?
More specifically, for Java libraries, what makes them an API and/or SPI?
Put differently, the API tells you what a specific class/method does for you, and the SPI tells you what you must do to conform.
Usually API and SPI are separate. For example, in JDBC the Driver
class is part of the SPI: If you simply want to use JDBC, you don't need to use it directly, but everyone who implements a JDBC driver must implement that class.
Sometimes they overlap, however. The Connection
interface is both SPI and API: You use it routinely when you use a JDBC driver and it needs to be implemented by the developer of the JDBC driver.
@SomeAnnotation
to my class to get it picked up by some framework, would this annotation class SomeAnnotation.class
be considered part of the SPI, even though I am not technically extending or implementing it? –
Aronarondel .spi
. One other case I can think of is when an SPI type is annotated because this annotation is used in the internals of the component/app that the SPI is for. You can see an SPI as an extension/plugin point that allows swappable implementations for (part of) the component. –
Quinate From Effective Java, 2nd Edition:
A service provider framework is a system in which multiple service providers implement a service, and the system makes the implementations available to its clients, decoupling them from the implementations.
There are three essential components of a service provider framework: a service interface, which providers implement; a provider registration API, which the system uses to register implementations, giving clients access to them; and a service access API, which clients use to obtain an instance of the service. The service access API typically allows but does not require the client to specify some criteria for choosing a provider. In the absence of such a specification, the API returns an instance of a default implementation. The service access API is the “flexible static factory” that forms the basis of the service provider framework.
An optional fourth component of a service provider framework is a service provider interface, which providers implement to create instances of their service implementation. In the absence of a service provider interface, implementations are registered by class name and instantiated reflectively (Item 53). In the case of JDBC, Connection plays the part of the service interface, DriverManager.registerDriver is the provider registration API, DriverManager.getConnection is the service access API, and Driver is the service provider interface.
There are numerous variants of the service provider framework pattern. For example, the service access API can return a richer service interface than the one required of the provider, using the Adapter pattern [Gamma95, p. 139]. Here is a simple implementation with a service provider interface and a default provider:
// 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();
}
}
The difference between API and SPI comes when an API additionally provides some concrete implementations. In that case, the service provider has to implement a few APIs (called SPI)
An example is JNDI:
JNDI provides interfaces & some classes for context lookup. The default way to lookup a context is provided in IntialContext. This class internally will use SPI interfaces (using NamingManager) for provider specific implementations.
See the JNDI Architecture below for better understanding.
API stands for Application Programming Interface, where API is a means for accessing a service / function provided by some kind of software or a platform.
SPI stands for Service Provider Interface, where SPI is way to inject, extend or alter the behavior for software or a platform.
API is normally target for clients to access a service and it has the following properties:
-->API is a programmatic way of accessing a service to achieve a certain behavior or output
-->From API evolution point of view, addition is no problem at all for clients
-->But API's once utilized by clients it can not (and should not) be altered / deleted unless there are an appropriate communications, since its a complete degradation of the client expectation
SPI on the other part are targeted for providers and has the following properties:
-->SPI is a way to extend / alter the behavior of a software or a platform (programmable vs. programmatic)
-->SPI evolution is different from API evolution, in SPI removal is not an issue
-->Addition of SPI interfaces will cause problems and may break existing implementations
For more explanation click here : Service Provider Interface
NetBeans' FAQ: What is an SPI? How is it different from an API?
API is a general term - an acronym for Application Programming Interface - it means something (in Java, usually some Java classes) a piece of software exposes, which allows other software to communicate with it.
SPI stands for Service Provider Interface. It is a subset of all things that can be API specific to situations where a library is providing classes which are called by the application (or API library), and which typically change the things the application is able to do.
The classic example is JavaMail. Its API has two sides:
- The API side — which you call if you are writing a mail client or want to read a mailbox
- The SPI side if you are providing a wire-protocol handler to allow JavaMail to talk to a new kind of server, such as a news or IMAP server
Users of the API rarely need to see or talk to the SPI classes, and vice-versa.
In NetBeans, when you see the term SPI, it is usually talking about classes that a module can inject at runtime which allow NetBeans to do new things. For example, there is a general SPI for implementing version control systems. Different modules provide implementations of that SPI for CVS, Subversion, Mercurial and other revision control systems. However, the code that deals with files (the API side) does not need to care if there is a version control system, or what it is.
There is one aspect which doesn't seem to be highlighted much but is very important to understand why and when to use API/SPI.
API/SPI split is only required when you actually write a platform that has at least one third-party client. If you're not writing platform and have all the API consumer code under control, the only benefit will be good & clean object design as you can refactor it any time.
But once you have at least one third-party client of your platform and you want to do changes in backward compatible way, you should most probably use API/SPI split.
Lets show it on one of the well known Java objects Collection
and Collections
.
API: Collections
is a set of utility static methods. Often classes representing API object are defined as final
as it ensures (at compilation time) that no client can ever "implement" that object and they can depend on "calling" its static methods, e.g.
Collections.emptySet();
Since all clients are "calling" but not "implementing", authors of JDK are free to add new methods into the Collections
object in the future version of JDK. They can be sure it can't break any client, even if there are probably milions of usages.
SPI: Collection
is an interface which implies that anyone can implement her own version of it. Thus, authors of JDK can't add new methods into it as it would break all clients who wrote their own Collection
implementation (*).
Typically when additional method is required to be added, new interface, e.g. Collection2
which extends the former one needs to be created. SPI client then can decide whether to migrate to the new version of SPI and implement it's additional method or whether to stick with the older one.
You might already seen the point. If you combine both pieces together into a single class, your API is blocked from any additions. That's also the reason why good Java APIs and Frameworks don't expose abstract class
as they would block their future evolution with respect to the backward compatibility.
If something is still unclear, I recommend to check this page which explains the above in more detail.
(*) Note this is true only until Java 1.8 which introduces concept of default
methods defined in an interface.
I suppose an SPI slots into a larger system by implementing certain features of an API, and then registering itself as being available via service lookup mechanisms. An API is used by the end-user application code directly, but may integrate SPI components. It's the difference between encapsulation and direct usage.
Service provider interface is the service interface which all providers must implement. If none of the existing provider implementations work for you, you need to write your own service provider (implementing the service interface) and register somewhere (see the useful post by Roman).
If you're reusing the existing provider implementation of the service interface, you're basically using the API of that particular provider, which include all the methods of service interface plus a few public methods of its own. If you're using methods of provider API outside the SPI, you're using provider specific features.
In the Java world, different technologies are meant to be modular and "pluggable" into an application server. There is then a difference between
Two examples of such technologies are JTA (the transaction manager) and JCA (adapter for JMS or database). But there are others.
Implementer of such a pluggable technology must then implement the SPI to be pluggable in the app. server and provide an API to be used by the end-user application. An example from JCA is the ManagedConnection interface which is part of the SPI, and the Connection that is part of the end-user API.
© 2022 - 2024 — McMap. All rights reserved.