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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With