I keep wanting to try this on a larger scale with our app + build system, but higher priorities keep pushing it to the back burner. It seems like a nice way to load Guice modules and avoids the common complaint about "hard coded configuration". Individual configuration properties rarely change on their own, but you will almost always have a set of profiles, usually for different environments (Debug, Production, etc).
ServiceLoader lets you pull a list of all implementations defined as a service for a given type. Putting this together with Guice, you end up with:
import java.util.ServiceLoader;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
public class ModuleLoader<M extends Module> extends AbstractModule {
private final Class<M> type;
public ModuleLoader(Class<M> type) {
this.type = type;
}
public static <M extends Module> ModuleLoader<M> of(Class<M> type) {
return new ModuleLoader<M>(type);
}
@Override
protected void configure() {
ServiceLoader<M> modules = ServiceLoader.load(type);
for (Module module : modules) {
install(module);
}
}
}
Usage example (as a dynamic servlet loader in a guice-servlet project):
import com.google.inject.servlet.ServletModule;
public class ServletLoader extends GuiceServletContextListener {
@Override
protected final Injector getInjector() {
return Guice.createInjector(ModuleLoader.of(ServletModule.class);
}
}
The services (packaged as modules) would be packaged in seperate jar files. Within each one you'd define the class(es) in the meta-data:
Within servlets.jar: META-INF/services/com.google.inject.Module
com.example.webapps.MyServletModuleA
com.example.webapps.MyServletModuleB
Since we use Maven, we think this would be ideal as we could pull in different implementations at runtime via profile dependencies. Is anyone using Guice like this?
If not, feel free to use this example and see how it works for you. (ServiceLoader is only supported in JDK6+)