<< View previous version | view page history | view next version >>
Introduction
When we use an approach service based we have to deal with interfaces (i.e. contracts), factories and implementations. We need a mechanism to discovery the right implementation for specific service. A commons solution is to use a system property that contain the full qualified name (FQN) of the implementation class and then the factory will use this to instantiate the implementation. Service Provider Interface allow us to use a standard technique to discovery a right implementation on a desired interface (i.e. contract )
SPI
This technique consist of put a file, whose name is contract's name , within jar under path META-INF/services. For example if the interface is org.bsc.spi.MyContract into the jar the file will be:
META-INF/services/org.bsc.spi.MyContract
and within this file must be put just one line containing the FQN of the implementation.
At this point the steps to create a SPI application will be:
- create a contract (i.e. project containing interface)
- create a provider that implements the contract and publish implementation through SPI service
- create a factory (consumer) that discovery implementation and return the instance
Java Example
Create a contract
package org.bsc.spi; public interface MyContract { String test(); }
Create a provider
As provider we mean an implementation of a contract. See example below:
public class MyProvider implements MyContract { public String test() { return "hello world!"; } }
To publish this provider through the SPI we have found a very useful project https://metainf-services.dev.java.net/ that allow us to write the SPI infos simply using the annotation @MetaInfServices. See example below
@MetaInfServices public class MyProvider implements MyContract { public String test() { return "hello world!"; } }
to use this project from maven you have to put the following dependency in your pom
<repositories> <repository> <id>java.net</id> <url>http://download.java.net/maven/2/</url> </repository> </repositories> <dependencies> <dependency> <groupId>org.kohsuke.metainf-services</groupId> <artifactId>metainf-services</artifactId> <version>1.1</version> <optional>true</optional> <type>jar</type> </dependency>
Note: optional means that this dependency will be not include in project that refer to your provider project. Run clean & install (or package) and automatically the SPI information will be included in your jar
Create a Factory
Finally we can develop the factory that discover provider and instantiate it
public class MyContractFactory { public static MyContract createInstance() throws Exception { java.io.InputStream is = MyContractFactory.class.getClassLoader().getResourceAsStream("META-INF/services/org.bsc.spi.MyContract"); java.io.LineNumberReader r = new LineNumberReader( new java.io.InputStreamReader(is)); String fqn = r.readLine(); return (MyContract)Class.forName(fqn).newInstance(); } }