Archive August 2009

Toggle view

ServiceLoader or "Sometimes you just don't need a full blown dependency injection container"

I like Springframework very much and use it in my day to day business as it eases development in many places. A few days ago I started using Hibernate Envers in order to implement a simple auditing solution for a JPA based application. I was faced with the (typical) requirement that the username of the user currently logged in was written into the audit entity. With Envers you would do that using a org.hibernate.envers.RevisionListener. This is instantiated by the Envers runtime. That listener required access to the FacesContext (it’s a JSF based application) to get the user principal from the HTTP request. Not a big deal in general! Still I wanted to keep that testable and usable in various environments, so an abstraction was needed and finally something would have to inject that into my listener.
As I said I’m a fan of Spring and this would be the perfect job and eventually one would propose “yeah, let’s do Spring AOP with AspectJ weaving”. As this application was already in production I didn’t want to add that at this time and was seeking for something more simple but still elegant.

Java as of 1.6 has the concept of SPI and ServiceLoader already built-in. I had never used it before. Here it seemed to perfectly match and it did.

import java.security.Principal;
public interface UserPrincipalProvider {
	Principal getUserPrincipal();
}

import java.security.Principal;
public class TestUserPrincipalProvider implements UserPrincipalProvider {

	public Principal getUserPrincipal() {
		return new Principal() {
			public String getName() {
				return "TEST";
			}
		};
	}
}

A file named META-INF/services/at.package.auditing.UserPrincipalProvider would be responsible for registering the provider implementation, it only contains one or multiple class names:

at.package.auditing.TestUserPrincipalProvider

For getting a runtime instance of such a provider I implemented a helper like

public static <T> T lookup(Class<T> clazz) {
	Iterator<T> iterator = ServiceLoader.load(clazz).iterator();
	return iterator.hasNext() ? iterator.next() : null;
}

It is called like ...lookup(UserPrincipalProvider.class).

green red blue grey