Java, The Service Locator and Modules
One of the frustrations I faced whilst becoming Java certified, was the questions on the service locator design pattern and its use with Java’s Module system.
I found precious little resources on this combination, and none outside the official study guide that used the same terminology as the official practice exams.
Even guides to the module system that I found, were wrapped in their own example code, thus difficult to extrapolate to Oracle’s example of the Service Locator.
What I’d like to cover in this insight, is a simple example of the Service Locator design pattern implemented using modules, to give you a helping hand for the Java 11 certification exam.
Some Quick Definitions
The Way The Book Has It
I’ve put together an example on Github where you can see a full implementation of the design pattern using the module system, with all the modules named as they are referred to in the book, but let me talk through them here.
The Service Provider Interface
This is the module that contains the interface that shall be provided. Which means that it ‘exports’ said interface and all the other modules need a statement for ‘requires’ this module.
module serviceProviderInterface{exports thepackage.interfacepackage;
}
The Service Locator
This is the module that includes the code to locate implementations of the interface. It’s the only module that has the ‘uses’ directive, but don’t let that fool you in the exam. it also needs access to the service provider interface and it ‘exports’ the package containing the service locator code.
module serviceLocator{
requires serviceProviderInterface;
uses thepackage.interfacepackage.ServiceProviderInterface; exports thepackage.locatorpackage;}
It is assumed here that the ‘thepackage.locator package’ contains a method somewhere which uses the ServiceLoader class and returns the interface using the following code somewhere:
ServiceLoader<ServiceProviderInterface> loader = ServiceLoader.load(ServiceProviderInterface.class);
I did this using some simple static methods, which are not much removed from the example in the book.
The Consumer
The consumer module ‘requires’ both the Service Provider Interface and the Service Locator modules.
module consumer {
requires serviceLocator;
requires serviceProviderInterface;
}
Of course without an implementation the ServiceLoader will never return anything, but nothing that has come so far has needed to reference the implementation.
The Service Provider
The service provider module ‘provides’ the interface ‘with’ a concrete class. So if you see the ‘provides’ directive think Service Provider, but once again don’t let the exam fool you. This module also needs access to the interface module.
module serviceProvider{
requires serviceProviderInterface; provides thepackage.interfacepackage.ServiceProviderInterface with thepackage.providerpackage.ServiceProvider;
}
Running the Code
The modules are compiled using ‘javac’, packaged using the ‘jar’ command and placed in a common folder, to be used as the module path. Then the java command needs to specify the module path and the location of the main method:
java -p mods -m consumer/thepackage.consumerpackage.Consumer
I wrote a bash script to do all this for me, if you are unsure of the correct arguments. Saying that, the exam expects you to know how to use the command line, when it comes to the module system. I just don’t feel I have the word count to cover that topic here. Sorry!
Combining Modules
I can cover another point or two I can for the exam though. Firstly, the Service Provider Interface and the Service Locator are considered to be parts of the Service. The Service Provider itself is not. Secondly, you are expected to know what the above pattern looks like if you were to combine any two of the modules into one. What needs to be remembered is that you don’t need to export anything that is only used internally to the new module.
For my example I combined the Service Provider Interface and the Service Locator into one module that I called the Service.
module service{
exports thepackage.interfacepackage; uses thepackage.interfacepackage.ServiceProviderInterface; exports thepackage.locatorpackage;
}
I needed to tweak my lovely bash script, but it all worked.
A Star Wars Example
All the other blogs I read didn’t rely on examples out of pure foolishness. Examples add context. Considering how dry everything I wrote so far is, I feel the need to add some space fantasy to the mix. So, back on github, I took my original 4 module example and replaced all the names with more thematic ones:
Old Module Name
New Module Name
serviceProviderInterface
rebelHero
serviceLocator
rebelHeroLocator
consumer
rebelRecruiter
serviceProvider
heroProvider
I also replaced all the package and class names, but I don’t feel that illustrates anything beyond my own descent into madness. The bash script to package and run it simply runs it three times to illustrate the recruitment of three Jedi to the rebel cause!
##### Running the Consumer #####
We have recruited: Luke Skywalker
We have recruited: Corran Horn
We have recruited: Yoda
You can see how we might add a new implementation of the Hero interface, say AcePilots, in the heroProvider, and modify its module-info file to allow them to be found by the rebelHeroLocator.
provides thepackage.heroInterfaces.Hero with thepackage.heros.Jedi, thepackage.heros.AcePilot;
One could even add a new module of mercenaries that mirror the structure of the given Service Provider to add a new type of anti-hero to the mix.
Passing The Exam
The Java 11 exam is full of trick questions, but when it comes down to specialised knowledge, there are fewer tricks. It’s likely that all questions you get on the module system will be straight tests of your knowledge. It’s my hope that I have given you at least four percent by writing this. Saying that, modules and the service locator pattern are not the only place where the exam uses bespoke language, so I would still recommend getting hold of the official books.
Until the next time I feel like going on a code related rant, may the force be with you.