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
| 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); | |
| } | |
| } |
| 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 | |
| } | |
| } |
| 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.
thank you very much for this awesome tutorial,
for dagger 2 (the new version) will the code still the same
I think it will work, but there’s likely a cleaner approach: 1) annotate each dependency with `@Inject` (javax.inject.Inject); 2) in `BaseServlet.init()`, call `this.objectGraph.inject(this)`. This avoids need for `this.dependency = this.get(Dependency.class);` for each dependency class.