Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HowTo have multiple SPI implementations in one JAR

Tags:

java

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?

like image 341
micfra Avatar asked Nov 26 '13 15:11

micfra


1 Answers

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 BeanDefinitions that a BeanFactory uses to create spring beans for the ApplicationContext. See e.g. spring-tx.

like image 104
René Link Avatar answered Nov 01 '22 17:11

René Link