Many developers seek to separate API interfaces and abstract classes from their implementation in separate packages. Yet, this almost always leads to cycles between java packages (api refers to impl, and vice-versa). There has been many frameworks, such as OSGi, supporting modularization, but the documentation has not always been good and complete. Many developers have struggled with class loading issues too.
Fortunately, Java has delivered the ServiceLoader utility since release 6. The example described in this post is available from Github in the Java-ServiceLoader directory. It is inspired from here.
Service & Implementation
We define a simple interface and its implementation:package com.service.API; public interface MyService { long getTime(); } package com.service.API.Impl; import com.service.API.MyService; public final class MyServiceImpl implements MyService { public MyServiceImpl() { }; @Override public long getTime() { return System.currentTimeMillis(); } }
Service Loading
Next, we declare the implementation in a file having the fully qualified name of the API under the META-INF/services directory in the .jar:The file contains fully qualified name of the implementation:
com.service.API.Impl.MyServiceImpl
Next, we load the service using the ServiceLoader:
public class MyApp { public static <T> T loadService(Class<T> api) { T result = null; ServiceLoader<T> impl = ServiceLoader.load(api); for (T loadedImpl : impl) { result = loadedImpl; if ( result != null ) break; } if ( result == null ) throw new RuntimeException( "Cannot find implementation for: " + api); return result; } public static final MyService myService = loadService(MyService.class); public static void main(String[] args) { System.out.println("Time is: " + myService.getTime()); } }