It is common to accomodate multiple service providers while designing an API. Each service provider may implement a use-case that will be used by API client applications. For example, Java security has a number of providers SunJCE, BKS etc which provide security operations such as encryption. Two common patterns that come into play involve defining service provider interfaces, factory classes/methods to get the appropriate target object. Service provider interface is implemented by the service provider classes and there may be more than one type of class that provides a functionality like encryption. There are DESCipher, AESCipher etc all of which implement CipherSpi which is the service provider interface definition. Again the Cipher engine class encapsulates a CipherSpi and creates the appropriate cipher through its factory method getInstance(). The provider list is usually read from a configuration file. Here we use a simple example to demonstrate spis, spiImpls.
Suppose we want a logger. We can define the logger spi which has the functionalities that we want from a logger. We provide two implementations of this spi and annotate the classes with spiImpl. This annotation is not mandatory. The class name can be anything but, if name conventions are followed then, code becomes maintainable in addition to being simpler. The engine class can be Logger which takes a string parameter which specifies whether we need a File based logger or a Console logger. The Logger class acts like a factory for creating Logger classes and allows client apps to perform logging through it. Although this is a small example, it gets the idea across. SPI, SPIImpl classes are very frequently used in Java 2 Enterprise projects just like Facade pattern. The spi pattern allows us to add different types of providers and also implementations of the interface.
Here is the structure for the project packages.
The sample SPI
Spi Implementation example
Application using Logger