Guice Webapp Insight

guice web dataflow:

Basic Design Concept:

  1) HttpRequest/HttpResponse will always be created by WebContainer(jetty/tomcat) and Guice will reuse/wrap them.

  2) For Servlet that match the url pattern in ServletModule, they will be created by Guice instead, their service() will called by guice filtering.

  3) For Servlet that doesn't match the url pattern defined in ServletModule, they will be created by WebContainer directly.

 

1) Listener:

<listener>
	<listener-class>edu.xmu.webapp.core.MyListener</listener-class>
</listener>
public class MyListener extends GuiceServletContextListener {
	@Override
	protected Injector getInjector() {
		return Guice.createInjector(new MyServletModule());
	}
}
public class MyServletModule extends ServletModule {
	@Override
	protected void configureServlets() {
		serve("*.html").with(MyServlet.class);
	}
}

2) Listener startup:

public abstract class GuiceServletContextListener
    implements ServletContextListener {
  public void contextInitialized(ServletContextEvent servletContextEvent) {
    final ServletContext servletContext = servletContextEvent.getServletContext();

    GuiceFilter.servletContext = new WeakReference<ServletContext>(servletContext);

    Injector injector = getInjector(); // will invoke our own getInjector() in listener; MyServletModule.configureServlets() will be invoked
    injector.getInstance(InternalServletModule.BackwardsCompatibleServletContextProvider.class)
        .set(servletContext);
    servletContext.setAttribute(INJECTOR_NAME, injector);
  }
}
// MyListener
@Override
protected Injector getInjector() {
	return Guice.createInjector(new MyServletModule());
}
// Guice
public static Injector createInjector(Stage stage,
   Iterable<? extends Module> modules) {
   return new InternalInjectorCreator()
     .stage(stage)
     .addModules(modules)
     .build();
}
// Elements
public static List<Element> getElements(Stage stage, Iterable<? extends Module> modules) {
  RecordingBinder binder = new RecordingBinder(stage);
  for (Module module : modules) {
    binder.install(module); // here our own module(MyServletModule) will be installed
  }
  return Collections.unmodifiableList(binder.elements);
}
// MyServletModule
@Override
protected void configureServlets() {
	serve("*.html").with(MyServlet.class);
}

3) Filter:

<filter>
	<filter-name>guiceFilter</filter-name>
	<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>guiceFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

4) Serve Request with guice created servlet:

    Request URL:

http://localhost:8080/webapp-core/aaa.html
// GuiceFilter
public void doFilter(ServletRequest servletRequest,
    ServletResponse servletResponse, FilterChain filterChain) {
 filterPipeline.dispatch(servletRequest, servletResponse, filterChain);
}
// ManagedFilterPipeline
public void dispatch(ServletRequest request, ServletResponse response,
    FilterChain proceedingFilterChain) {
  new FilterChainInvocation(filterDefinitions, servletPipeline, proceedingFilterChain)
        .doFilter(withDispatcher(request, servletPipeline), response);
}
// FilterChainInvocation
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse){
  servletPipeline.service(servletRequest, servletResponse);
}
// ServletPipeline
public boolean service(ServletRequest request, ServletResponse response) {
  //stop at the first matching servlet and service
  for (ServletDefinition servletDefinition : servletDefinitions) {
    if (servletDefinition.service(request, response)) { // Here our own servlet is invoked
      return true;
    }
  }
  //there was no match...
  return false;
}

5) Serve Request with web container created servlet:

http://localhost:8080/webapp-core/formalServlet
<servlet>
	<servlet-name>formalServlet</servlet-name>
	<servlet-class>edu.xmu.webapp.servlet.FormalServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>formalServlet</servlet-name>
	<url-pattern>/formalServlet</url-pattern>
</servlet-mapping>
// GuiceFilter
public void doFilter(ServletRequest servletRequest,
    ServletResponse servletResponse, FilterChain filterChain) {
  filterPipeline.dispatch(servletRequest, servletResponse, filterChain);
}
// ManagedFilterPipeline
public void dispatch(ServletRequest request, ServletResponse response,
    FilterChain proceedingFilterChain) {
  new FilterChainInvocation(filterDefinitions, servletPipeline, proceedingFilterChain)
      .doFilter(withDispatcher(request, servletPipeline), response);
}
// FilterChainInvocation
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
      throws IOException, ServletException {
  index++;

  // Our url doesn't match any of defined guice serve url, thus serviced is false
  final boolean serviced = servletPipeline.service(servletRequest, servletResponse);

  //dispatch to the normal filter chain only if one of our servlets did not match
  if (!serviced) {
    proceedingChain.doFilter(servletRequest, servletResponse);
  }
}
// proceedingChain is an instance of "FilterChain", it will invoke all the following filters configed in web.xml, and then invoke correspond service() in target Servlet.
// From here, guice has transferred the filter/servlet control to web container(tomcat/jetty).

 

Reference Links:

1) http://insidecoding.com/2013/02/05/using-google-guice-in-web-applications/

 

你可能感兴趣的:(Guice,webapp)