As we said there is only one instance of javax.servlet.ServletContext(as long as we don't have a distributed application). We can trigger the initialization of the ServletContext using ServletContextListener. All we have to do is to implement the ServletContextListener.contextInitialized to create the google guice injector, and to set it as an attribute in the ServletContext:
package com.exam.web.guice; import java.lang.reflect.InvocationTargetException; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; public class GuiceServletContextListener implements ServletContextListener { public static final String KEY = Injector.class.getName(); public void contextInitialized(ServletContextEvent servletContextEvent) { servletContextEvent.getServletContext() .setAttribute(KEY, getInjector(servletContextEvent.getServletContext())); } public void contextDestroyed(ServletContextEvent servletContextEvent) { servletContextEvent.getServletContext().removeAttribute(KEY); } @SuppressWarnings("unchecked") private Injector getInjector(ServletContext servletContext) { String className = servletContext.getInitParameter("module"); try { Class module = (Class ) Class.forName(className); return Guice.createInjector(module.getConstructor().newInstance()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } } }
Then we have to change the web.xml to define the listener to be used by the web application container:
<listener> <listener-class> com.exam.web.guice.GuiceServletContextListener </listener-class> </listener>
We use web.xml to define which module to be used by Guice in
String className = servletContext.getInitParameter("module");
The class name is defined like this in web.xml:
<context-param>module</param-name> com.webapplication.bus.HibernateDaoModule</param-value> <description>Guice Module to be used for the servlets app</description> </context-param>
Finally in the servlet we can use this expression to get the injector:
(Injector) servletContext.getAttribute(GuiceServletContextListener.KEY)
We can add an injector field to the servlet and "inject" the injector into it when the servlet is initialized(a super servlet class can be created to define this code in only one place):
public class MyServlet extends HttpServlet { Injector injector; ... @Override public void init(ServletConfig config) throws ServletException { HibernateUtil.Configure(true); ServletContext servletContext = config.getServletContext(); injector = (Injector) servletContext.getAttribute(GuiceServletContextListener.KEY); injector.injectMembers(this); managersRegistry = injector.getInstance(ManagersRegistry.class); super.init(config); } }