I couldn’t find a great example of using the Dagger dependency injection framework in a Java servlet, so I’m publishing some of the key bits of what I did in the hopes of saving others some hassle.
What’s Dagger? A lightweight dependency injection framework, from Square. Particularly popular for Android projects, and implements standard JSR 330 annotations. So easy to move up to Guice later if you need a reacher DI solution.
How? The general idea, following this Stack Overflow answer, is to use a ServletContextListener
to initialize Dagger, build your object graph, and inject it into the ServletContext
. In the servlet’s init method, you can then use that graph. I’ve tried to provide a more precise outline of this in code below:
Details
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dagger.ObjectGraph; | |
public abstract class BaseServlet extends HttpServlet { | |
private ObjectGraph graph; | |
/** | |
* inits the Servlet with the object graph from Dagger | |
* if you override this, be sure your implementation calls that of this super class | |
* | |
* @param config | |
*/ | |
public void init(ServletConfig config) { | |
this.graph = (ObjectGraph) config.getServletContext().getAttribute(DIListener.ATTR_OBJECT_GRAPH); | |
} | |
/** | |
* used to get injected instances | |
* | |
* @param arg | |
* @return | |
*/ | |
public <T> T get(Class<T> arg) { | |
return this.getObjectGraph().get(arg); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.servlet.ServletContextEvent; | |
import javax.servlet.ServletContextListener; | |
import dagger.ObjectGraph; | |
/** | |
* DaggerListener – inits objectgraph and sets it in ServletContext, so it can be accessed in servlet's init() method | |
* | |
* @author Erik Schultink <erik@engetc.com> | |
*/ | |
public class DIListener implements ServletContextListener { | |
static final public String ATTR_OBJECT_GRAPH = "ObjectGraph"; | |
ObjectGraph objectGraph; | |
/*** | |
* called when servlet initialized | |
* | |
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) | |
*/ | |
@Override | |
public void contextInitialized(ServletContextEvent sce) { | |
//your object graph is initialized here, from your Dagger Module(s) | |
this.objectGraph = ObjectGraph.create(new ProductionModule()); | |
sce.getServletContext().setAttribute(ATTR_OBJECT_GRAPH, this.objectGraph); | |
} | |
/** | |
* no-op | |
* | |
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) | |
*/ | |
@Override | |
public void contextDestroyed(ServletContextEvent sce) { | |
//do nothing | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ExampleServlet extends BaseServlet { | |
//some dependency that the servlet needs | |
private Dependency dependency; | |
public void init(ServletConfig config) { | |
super.init(config); | |
this.dependency = this.get(Dependency.class); | |
} | |
//you're now free to implement doGet()/etc as you wish | |
//dependency should be defined, with the binding provided by the Dagger Module | |
… | |
} |
If you’re using Eclipse, getting Dagger’s code generation working properly can also be a bit tricky. The bit in this answer about the JARs to include under Project Settings -> Java Compiler -> Anotation Processing –> Factory Settings helped me.