Service Provider Interface: Creating Extensible Java Applications
A SPI Case Study
This section demonstrates a service provider for retrieving weather-related information defined by a Weather SPI and the load() and iterators() methods of the ServiceLoader API. The weather service has a single goal: retrieving weather-related information such as temperature and rainfall for a given location, given the city name or zip code.
Figure 2 shows a class diagram of the service provider for the Weather SPI.
Figure 2. Class Diagram of the Service Provider for Weather SPI: The weather service has a single goal: retrieving weather-related information for a given location.
- Weather: This class defines the SPI specification for weather service. It has two overloaded methods that define the behavior: retrieving the weather reading given the city name or zip code.
- WeatherReading: This auxiliary class supports the specification that has the return types defined.
- WeatherServiceProvider: This class provides the implementation logic for the Weather SPI. It maintains two different collections: one for storing city names and their related weather information and another for storing zip codes and their related weather information.
A provider may spread across multiple classes, and a more elaborate design may fill in the collections by using a web service to connect to the vendor site. But for demonstration purposes, this simple class should suffice. The following listing demonstrates the logic of the service provider for the Weather SPI:
Registering the Service Provider
Now that the service provider is complete, it's time to register it via the configuration file under META-INF-/services. You can use the following process to do so. (Note that the file name is the name of the specification class. The contents of the file reflect the concrete name of the service provider class that implements the SPI specification.)
- Create a directory META-INF/services in the project, if it does not exist already.
- Create the configuration file com.weather.spi.Weather in the project under META/Services.
- Add the contents com.weather.spi.WeatherServiceProvider to the file com.weather.spi.Weather as a single-line listing.
- JAR up the contents as shown in Figure 3 below. (You could use the export feature in Eclipse to create and save the JAR file).
Figure 3. JAR for Service Provider Registration: Here is how to register the service provider via the configuration file under META-INF-/services.
Design Patterns That Support SPI
A pattern is a standard or reusable solution to a common problem, and a design pattern is a template for the relationships and interactions between classes or objects. A design pattern hints at different implementation possibilities while providing a general solution to a problem. A design pattern needs to be translated into code and could be implemented in several different ways based upon the situation.
In the Singleton pattern, only a single instance of a class is ever created. From a design perspective, only a single class or object assumes the responsibility for insuring that a Singleton is created only once.
The considerations for creating Singletons in Java include:
- Declare the single instance of the class as private and static.
- Hide the constructor of a Singleton by declaring private.
- The constructor will initialize the single instance.
- Provide a global point of access to the single instance via getInstance() or an equivalent.
- Synchronize the global point of access to make it thread safe.
The above techniques apply to the simplest form of creating a Singleton in a non-cluster environment. If the constructor needs parameters, you add a static factory method such as createInstance(ParameterList...). If you decide not to synchronize the getInstance(), refer to more detailed techniques such as double-checked locking pattern or extending a Singleton.
Page 2 of 3