如果你已经增加了GuiceFilter并且运行, Guice Servlet就已经建立. 不管如何, 你将要安装一个ServletModule的实例一边真正的使用Guice Servlet :
Guice.createInjector(new ServletModule());
这个模块创建request和session的周期中,并且提供一个配置filter和Servlet的地方。这时在你想要找个地方自由的创建注入器(injector),通常这个地方是在一个ServletContextListener中。
ServletContextListener是个在web应用部署后就触发的Java servlet 组件,时机是在任何请求到达之前。Guice Servlet 提供了一个便利的实用程序,你可以编写他的子类以便注册你的ServletContextListener:
public class MyGuiceServletConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new ServletModule()); } }
往下继续, 增加如下内容到 web.xml,这样servlet容器在程序部署完成后触发这个类 so the servlet container triggers this class when the app is deployed:
<listener> <listener-class>com.example.MyGuiceServletConfig</listener-class> </listener>
现在你可以在每个你需要的地方使用Guice Servlet了。注意,使用Guice Servlet 并不一定需要ServletContextListener。 只要你记住创建你的注入器的时候安装ServletModule就可以了。
ServletModule 是一个用内部编码方式的web.xml部署描述符的替代品。filter和Servlet使用普通java方法调用来配置。下面是个典型的在创建Guice注册器时注册一个servlet的例子:
Guice.createInjector(..., new ServletModule() { @Override protected void configureServlets() { serve("*.html").with(MyServlet.class); } }
这样注册了一个叫MyServlet的Servlet(一个HttpServlet的子类)对所有.html结尾的请求进行服务。. 你也可以使用路径风格的语法注册servlet,类似于web.xml里面的形式。:
serve("/my/*").with(MyServlet.class);
你也可以用非常简单的语法做Filter的映射:
filter("/*").through(MyFilter.class);
每个到来的请求都通过MyFilter处理。然后继续经过其他匹配的filter,最终被分发到实际处理的servlet。
注意:每个servlet(或者filter)需要注解为@Singleton。如果不能直接对这个类进行注解,你必须使用bind(..).in(Singleton.class)的方式使其成为@Singleton,独立于filter() 或者 servlet()规则。映射成其他的scope都是错误的。这是与Servlet保持一致的规范。Guice Servlet不支持过时的单线程模式(SingleThreadModel)。
安装这个Servlet模块后将你自动的可以访问一些servlet框架的类。这样非常有助于使用servlet编程模式并且可注入任何Guice默认注入的对象,当你安装ServletModule后:
@RequestScoped class SomeNonServletPojo { @Inject SomeNonServletPojo(HttpServletRequest request, HttpServletResponse response, HttpSession session) { ... } }
这个请求和响应(The request and response)周期是当前http请求。类似于http session对象周期是当前用户的session。另外你还可以注入当前的ServletContext,并且可以通过使用注解@RequestParameters映射请求的参数,像下面:
@Inject @RequestParameters Map<String, String[]> params;
这个必须是一个Map类型,并且map的value必须为String数组(译者注:必须为以上的代码形式),因为http协议允许多个值绑定到一个请求参数,尽管通常只有一个值。注意如果你想通过单实例或者更宽生命周期类访问request或者singletons session周期的类,你需要使用Provider<T>方式进行注入来代替普通的@Inject。
你可以随意按自己的喜好注册很多servlet和filter。他们将按ServletModule里面顺序比较和分发:
Guice.createInjector(..., new ServletModule() { @Override protected void configureServlets() { filter("/*").through(MyFilter.class); filter("*.css").through(MyCssFilter.class); // etc.. serve("*.html").with(MyServlet.class); serve("/my/*").with(MyServlet.class); // etc.. } }
这将按代码中从上到下的顺序进行适配。例如,一个url是/my/file.js首先与下面的映射匹配:
serve("*.html").with(MyServlet.class);
匹配失败后,将继续向下找下一个映射进行适配:
serve("/my/*").with(MyServlet.class);
一旦映射的规则匹配,Guice Servlet将分发请求给MyServlet并且停止继续匹配。这个规则同时适用于filter(规则就是,匹配与映射列表中的第一个匹配)。
以上两个映射规则也可以用更精简的可变参数与发来书写 syntax:
serve("*.html", "/my/*").with(MyServlet.class);
这种方式可以让你把多个URI映射到同一个servlet。filter也可以用类似的方式映射。
每个servlet都在请求周期中,由ServletModule 配置完成。
默认的,有一些可用元素可进行注入,每个都被绑定在请求周期内:
记住,如果一个类在请求周期外被创建并且注入点在类上时,要用Provider对这些元素进行注入,例如,一个单例的Servlet在请求周期外被创建,这样它在创建后才接受到request请求(通常是service()方法),就需要在请求周期依赖调用Provider.get()方法进行注册
The most common way to seed a value within RequestScope is to add a Filter in front of your servlet. This filter should seed the scope by adding the value as a request attribute.
For example, assume we want to scope the context path of each request as a String so that objects involved in processing the request can have this value injected.
过滤器可能如下:
protected Filter createUserIdScopingFilter() { return new Filter() { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // ...you'd probably want more sanity checking here Integer userId = Integer.valueOf(httpRequest.getParameter("user-id")); httpRequest.setAttribute( Key.get(Integer.class, Names.named("user-id")).toString(), userId); chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }; }
绑定可能像如下:
public class YourServletModule extends ServletModule { @Override protected void configureServlets() { ..... filter("/process-user*").through(createUserIdScopingFilter()); } }
And the servlet to use this might look like this:
@Singleton class UserProcessingServlet extends HttpServlet { private final Provider<Integer> userIdProvider; .... @Inject UserProcessingServlet( Provider<Integer> userIdProvider, .....) { this.userIdProvider = userIdProvider; } .... @Override public void doGet( HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ... Integer userId = userIdProvider.get(); } }
太多了,待续。。。