/ DECOUPLING, DEPENDENCY, DEPENDENCY INJECTION, DI, META-INF, OSGI, SERVICE LOCATOR, SERVICELOADER, SERVICES

Simplest Java decoupling without 3rd party frameworks

[…​] coupling (or dependency) is the degree to which each program module relies on each one of the other modules.
— Wikipedia
http://en.wikipedia.org/wiki/Coupling_(computer_science)

In object-oriented programming, removing dependencies is done by using interface. Thus, if class A is dependent on class B, we introduce interface C, which is implemented by B. Now A depends on C  (see below).

Programming by interface

This first step in decoupling is called programming by interface. Anyway, we still have to "feed" class A with a C interface, be it a B object or whatever instance that implements C. So, we need an instance of such a class. In a standard code, B is instantiated by class A in this fashion:

public class A {
    private C c = new B();
}

Oh dear! It seems we introduced the dependency from A to B again…​ Hopefully, there are answers to this problem, namely Dependency injection. In dependency injection, an external module is responsible for instantiating and setting the object of class B. The code becomes the following:

public class A {

    private C c;

    public void setC(C c) {
        this.c = c;
    }
}

Now, the dependency from A to B is removed. The DI framework creates a new B and pass it to the A object through the setter: it is the only component aware of (and thus dependent on) class B. Although DI is nowadays clearly mainstream, thanks largely to the Spring framework, there are other solutions to remove dependency. One such solution is the Service Locator core JEE pattern:

Service Locator pattern

In this diagram, the Client doesn’t reference the Target directly but gets it through an intermediary object called the Service Locator. This pattern is illustrated by the following code, which performs a JNDI lookup:

public class ServiceLocator {

    /** Singleton. */
    private static ServiceLocator me;

    /** JNDI context to connect to. */
    private final InitialContext context;

    /** Objects cache. */
    private Map cache;

    /**
     * Gets an instance of the locator.
     *
     * @return Singleton
     * @throws NamingException
     */
    public static ServiceLocator getInstance() throws NamingException {
        if (me == null) {
            me = new ServiceLocator();
        }
        return me;
    }

    private ServiceLocator() throws NamingException {
        context = new InitialContext();
    }

    /**
     * Get the object stored under the name in the JNDI tree. First look up in
     * the cache, then in the backing tree.
     *
     * @param name
     * @return Object stored
     * @throws NamingException
     */
    public Object lookup(String name) throws NamingException {
        Object object = cache.get(name);
        if (object == null) {
            object = context.lookup(name);
            cache.put(name, object);
        }
        return object;
    }
}

Obviously, this locator is very simple and adopts the simplest of caching strategies; yet, it works.

There’s another form of service locator that is not well known (read: only true geeks know about it) that is avalaible in JDK since Java 1.3: it is the Service Provider. This feature can be a life saver. It lets you, if you have cleanly separated JARs, one of interfaces (API) and one of implementations, to decouples your client code from the implementation altogether and use only the interfaces. How is it done?

First, you have to have your code cleanly separate interface and implementations (see above). Then, for each interface, create a new file that will take place in your implementation JAR under META-INF/services. The name of the file should be the fully qualified name of the interface and the content of the file should be the fully qualified name of the chosen implementation. Last, in your code, you should only use the following snippet:

java.util.ServiceLoader.load(MyFullyQualifiedInterfaceName.class);

That’s it, as long as you take care to put both interfaces and implementations JARs on the classpath. A word of warning though: if there’s more than one implementation on the classpath, the choice is not determined. Now you can astonish your fellow co-workers with this simple, yet powerful trick. If you know about OSGI, you can see that looks much like an embryo of OSGI service layer. The advantage of this solution is that you only need a JDK 1.3+. The drawback is that you can’t manage the lifecycle of your applications, it only provides services implementation.

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
Simplest Java decoupling without 3rd party frameworks
Share this