How to use Java ServiceLoader to create extensible applications

Since Java 6, a mechanism was introduced for Java code to automatically discover “plugin” service implementations for JARs within the classpath.

As well as being used by Java to find XML parsing & Image IO implementations, it’s an interesting mechanism & can be used to make user applications extensible too.

Define a Service

First, we’ll cover some quick terminology.

  • a ‘Service’ is the API you want plugins to be able to implement — probably an interface.
  • ‘Service Provider’ is the plugin, which you want to be able to discover & load automatically.
  • ‘Service Provider Interface’ (SPI) is the Service API with any associated classes; data-transfer objects, exceptions etc.

To define the Service, you should declare an interface or abstract class — for example, SearchService.

public interface SearchService {
    public List<Result> search (String text);
}

We can see here that a ‘Result’ class might be part of the SPI, and can be defined as part of the base Search service.

Create a Plugin

Since service implementations are found by JAR loading, you’ll probably need to define & build a JAR. This could be a separate or sub-project in your workspace.

Let’s suppose we are building a FuzzyTextSearch implementation of the SearchService.

Four simple steps are required:

  • you build a META-INF/services subdirectory into your JAR file.
  • in the ‘services’ directory, create a file for each service you are implementing. (in your case, this would be file META-INFA/services/some.package.SeachService).
  • in that file, declare the name of your implementation class(es).
  • you can then use the java.util.ServiceLoader API to discover & load registered services.

An example of the service provider file:

# providers of SearchService
# (comment lines begin with pound)
some.package.FuzzyTextSearch

Your application can then find and load service implementations like this:

ServiceLoader<SearchService> loader = ServiceLoader.load(SearchService.class);
for (SearchService plugin : loader) {
    // search via plugin...
}

The ServiceLoader mechanism enables your code to discover & use plugin implementations, without the base service being aware of or coded for the specific plugins you ship.

Conclusion

Service discovery & loading is an important mechanism which can be used for extensible applications, as well as being the means of extensibility within Java libraries.

Compared with other extensibility mechanisms (configuration-specific XML bean files, or Spring/ CDI component-scanning), ServiceLoader discovery provides a basic & effective plugin capability.

Pros: simple, easy to ease, fast loading. Con: similar to component-scanning, there is no ability to parameterize plugins.

Lastly, we’ll note that ServiceLoader is a Java standard; but that there are a few extra requirements to using it in OSGi environments. See the references if this is relevant to you.

See also:

Leave a Reply

Your email address will not be published. Required fields are marked *