What is the difference between Service Provider Interface (SPI) and Application Programming Interface (API)?
More specifically, for Java libraries, what makes them a
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.
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.
There is one aspect which doesn't seem to be highlighted much but is very important to understand the reasoning behind the existence of API/SPI split.
API/SPI split is only required when platform is expected to evolve. If you write an API and "know" it won't require any future improvements ever, there is no real reasons for splitting your code into the two parts (besides making clean object design).
But this is almost never the case and people need to have a freedom to evolve API together with future requirements - in a backward compatible way.
Note that all of the above assumes you're building platform that other people use and/or extend and not your own API where you have all client code under control and thus can refactor however you need.
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.