HowTo have multiple SPI implementations in one JAR

java

Solution

Just add multiple lines with the fully-qualified provider's class name

So if your SPI is `com.example.Marker`

META-INF/services/com.example.Marker

add each implementation in a new line

com.example.MarkerImplA
com.example.MarkerImplB
com.example.MarkerImplC

For details take a look at the JAR File Specification

Provider-Configuration File

A service provider identifies itself by placing a provider-configuration file in the resource directory META-INF/services. The file's name should consist of the fully-qualified name of the abstract service class. The file should contain a newline-separated list of unique concrete provider-class names. Space and tab characters, as well as blank lines, are ignored. The comment character is '#' (0x23); on each line all characters following the first comment character are ignored. The file must be encoded in UTF-8.

Provider lookup

Use the `ServiceLoader<T>` that was introduced in Java 1.6

ServiceLoader<Marker> markerLoader = ServiceLoader.load(com.example.Marker.class);
for (Marker marker : markerLoader ) {
     // select the marker you want or use all

     // only for demo
     System.out.println(marker);
}

Prior to 1.6 you have to implement the service loader by yourself or use a library. E.g. the apache discovery library's `Service`.

A note about plug-ins

It is possible to have multiple `META-INF/service` provider-configuration files in different deployment units, usually jar archives.

archive1.jar
 +- META-INF/services/com.example.Marker

archive2.jar
 +- META-INF/services/com.example.Marker

A lookup via the `ServiceLoader<T>` will pick up all implementations in all archives. This is done using `ClassLoader.getResources()`.

Thus you only have to add a jar to the classpath and the provided services can be picked up. That gives you the opportunity to build a plug-in architecture.

This is how spring works. You just add a jar to the classpath and spring features are available, because spring scans for it's service definitions. These definitions are named e.g. `spring.handlers`. Spring handlers are namespace handlers that extend the xml parsing to create `BeanDefinition`s that a `BeanFactory` uses to create spring beans for the `ApplicationContext`. See e.g. spring-tx.

Problem

Assume I have one interface `com.example.Marker` and I do have one implementation of this, eg `com.example.MarkerImplA`. To get one of them registered, I need to place a text file in `META-INF/services/com.example.Marker` looking like this ``` com.example.MarkerImplA ``` This works like a charme. Now, I have another implementation in the same jar file, eg `com.example.MarkerImpl2`. How do I achieve the registration of the second one?

Original source