One interface, many implementations is a very well known object oriented programming paradigm. If you write the implementations yourself then you know what those implementations are and you can write a factory class or method that creates and returns the right implementation. You might also make this config driven and inject the correct implementation based on configuration.
What if third parties are providing implementations of your interface? If you know those implementations in advance, then you could do the same as in the case above. But one downside is that code change is required to add or use new implementations or to remove them. You could come up with a configuration file, where implementations are listed and your code uses the list to determine what is available. Downside is that configuration has to be updated by you and this is non standard approach, in that, every API developer could come up with his own format for the configuration. Fortunately JAVA has a solution.
In JDK6, they introduced java.util.ServiceLoader, a class for discovering and loading classes.
It has a static load method that can be used to create a ServiceLoader that will find and load all of a particular Type.
public static<T> ServiceLoader <T > load(Class <T > service)
You would use it as
ServiceLoader<SortProvider> sl = ServiceLoader.load(SortProvider.class) ;
This creates a ServiceLoader that can find and load every SortProvider in the classpath.
The Iterator method returns an Iterator to the implementations founds that will be loaded lazily.
Iterator<SortProvider> it_sl = sl.Iterator() ;
You can iterate over what is found and store it in a Map or somewhere else in memory.
while (its.hasNext()) {
SortProvider sp = its.next() ;
log("Found provider " + sp.getProviderName()) ;
sMap.put(sp.getProviderName(),sp) ;
}
How does ServiceLoader know where to look ?
1. com.mj.msort.Sort is the main Sort API. It has 2 sort methods. One for Arrays and one of
collections. 2 implementations are provided - bubblesort and mergesort. But anybody can write additional implementations.
2. com.mj.msort.spi.SortProvider is the SPI.Third party implementors of Sort must also implement the SortProvider interface. The SPI provides another layer of encapsulation. We don't want to know the implementation details. We just want an instance of the implementation.
3. SPI providers need to implement Sort and SortProvider.
4. com.mj.msort.SortServices is a class that can discover and load SPI implementations and make them available to API users. It uses java.util.ServiceLoader to load SortProviders. Hence SortProvider also needs to be packaged as required by java.util.ServiceLoader for it to be discovered.
This is the class that brings everything together. It uses ServiceLoader to find all implementations of SortProviders and stores them in a Map. It has a getSort method that programmers can call to get a specific implementation or whatever is there.
5. Sample Usage
Sort s = SortServices.getSort(...
s.sort(...
In summary, ServiceLoader is a powerful mechanism to find and load classes of a type. It can used to build highly extensible and dynamic services. As an additional exercise, you can create your own implementation of SortProvider in your own jar and SortServices will find it as long as it is on the classpath.
What if third parties are providing implementations of your interface? If you know those implementations in advance, then you could do the same as in the case above. But one downside is that code change is required to add or use new implementations or to remove them. You could come up with a configuration file, where implementations are listed and your code uses the list to determine what is available. Downside is that configuration has to be updated by you and this is non standard approach, in that, every API developer could come up with his own format for the configuration. Fortunately JAVA has a solution.
In JDK6, they introduced java.util.ServiceLoader, a class for discovering and loading classes.
It has a static load method that can be used to create a ServiceLoader that will find and load all of a particular Type.
public static<T>
You would use it as
ServiceLoader<SortProvider
This creates a ServiceLoader that can find and load every SortProvider in the classpath.
The Iterator method returns an Iterator to the implementations founds that will be loaded lazily.
Iterator<SortProvider>
You can iterate over what is found and store it in a Map or somewhere else in memory.
while (its.hasNext()) {
SortProvider sp = its.next() ;
log("Found provider " + sp.getProviderName()) ;
sMap.put(sp.getProviderName(),sp) ;
}
How does ServiceLoader know where to look ?
- Implementors package their implementation in a jar
- jar should have a META-INF/services directory
- services directory should have a file whose name is the fully qualified name of the Type
- file has a list of fully qualified name of implementations of type
- jar is installed to the classpath
1. com.mj.msort.Sort is the main Sort API. It has 2 sort methods. One for Arrays and one of
collections. 2 implementations are provided - bubblesort and mergesort. But anybody can write additional implementations.
2. com.mj.msort.spi.SortProvider is the SPI.Third party implementors of Sort must also implement the SortProvider interface. The SPI provides another layer of encapsulation. We don't want to know the implementation details. We just want an instance of the implementation.
3. SPI providers need to implement Sort and SortProvider.
4. com.mj.msort.SortServices is a class that can discover and load SPI implementations and make them available to API users. It uses java.util.ServiceLoader to load SortProviders. Hence SortProvider also needs to be packaged as required by java.util.ServiceLoader for it to be discovered.
This is the class that brings everything together. It uses ServiceLoader to find all implementations of SortProviders and stores them in a Map. It has a getSort method that programmers can call to get a specific implementation or whatever is there.
5. Sample Usage
Sort s = SortServices.getSort(...
s.sort(...
In summary, ServiceLoader is a powerful mechanism to find and load classes of a type. It can used to build highly extensible and dynamic services. As an additional exercise, you can create your own implementation of SortProvider in your own jar and SortServices will find it as long as it is on the classpath.