Yet another way to get the Guice injector
Posted by David Chandler on December 16, 2009
I previously wrote about a way to get ahold of the Guice injector in a JSP by putting it in the ServletContext; however, I have another case where I need it in a class that doesn’t have access to the ServletContext, either. The class happens to be a background task that implements the Deferrable interface, which for sake of interface simplicity does not provide access to the ServletContext even though the task does in fact run in a servlet.
The solution is simply to create the Guice injector in a static factory:
package com.roa.server.guice; import com.google.inject.Guice; import com.google.inject.Injector; public class GuiceFactory { private static final Injector inj = Guice.createInjector(...); public static Injector getInjector() { return inj; } }
Now any class that needs access to a Guice-managed object can get it easily, including the ultra-simplified Guice context listener that’s registered in web.xml:
package com.roa.server.guice; import com.google.inject.Injector; import com.google.inject.servlet.GuiceServletContextListener; public class GuiceConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return GuiceFactory.getInjector(); } }
WARNING: this works fine in AppEngine because there’s only one WAR per JVM in that environment. If you’re not running in AppEngine and have multiple WARs in a single JVM, as is commonly the case, you may or may not want a single Guice injector for the whole JVM. I have not tested it, but I would think you wouldn’t be able to use Guice ServletModules in that case.
Dhanji said
Interesting post.
If it runs in a servlet can you not simply inject the injector (using Guice Servlet 2.0)?
Also, WARs have classloader isolation so you don’t share static fields between wars in a JVM.
Dhanji.
David Chandler said
Thanks, good to know. In this case, the code that needs the injector, while called from a servlet, is not created by Guice and therefore doesn’t have access to the Guice Injector. The class is a task implementing Deferrable and is executed by the Deferred servlet I’ve written about in another post. It is deserialized after being retrieved from the Datastore and then executed, providing no opportunity for Guice injection (at least not that I’m smart enough to implement).
-sowdri- said
Thanks David for pointing this out! Very helpful when you have to use Guice AOP with Deferred Task in Appengine.