当前位置: 代码迷 >> J2EE >> 『译』Java EE 六 Pocket.Guide—Servlets3.0(二)
  详细解决方案

『译』Java EE 六 Pocket.Guide—Servlets3.0(二)

热度:562   发布时间:2016-04-22 00:20:59.0
『译』Java EE 6 Pocket.Guide—Servlets3.0(二)

  Servlet Filters(过滤器)

?

  Servlet Filter(过滤器)用于从Servlet取得和更新request(请求)、response(响应)的内容和头信息,要注意的是Filter不创建response或者像servlets那样响应request 。认证、日志、数据压缩、加密是使用过滤器一些典型用途。 过滤器包装了一个servlet并作用于动态或静态内容。
  过滤器可以与一个servlet或与一组servlets、或指定的URL的静态内容向关联。过滤器由注解@WebFilter所定义:

@WebFilter("/*")public class LoggingFilter implements javax.servlet.Filter {  public void doFilter(HttpServletRequest request,HttpServletResponse response) {    //. . .  }}

?  代码表示,该Loggingfilter是适用于这个web程序所有的servlet和静态网页,这里@WebInitParam同样可用于指定初始化参数。一个过滤器和目标servlet总是在同一调用线程执行,多个过滤器可形成一个过滤器链。在部署描述符中一个过滤器由<filter>和<filtermapping>元素来定义:

<filter>  <filter-name>LoggingFilter</filter-name>  <filter-class>org.sample.LoggingFilter</filter-class></filter>. . .<filter-mapping>  <filter-name>LoggingFilter</filter-name>  <url-pattern>/*</url-pattern></filter-mapping>

?  除了使用@WebFilter和web.xml来配置过滤器,也可以用ServletContext.addFilter()方法来编程化定义,在ServletContainerInitializer.onStartup()方法或者ServletContextListener.contextInitialized()方法执行时来起作用,addFilter()方法返回一个ServletRegistration,动态的用来添加匹配URL映射、设置初始化参数和其他配置项:

@HandlesTypes(value = { HttpServlet.class })public class MyInitializer implements ServletContainerInitializer {  public void onStartup(Set<Class<?>> clazz, ServletContext context) {    FilterRegistration.Dynamic reg = context.addServlet("LoggingFilter","org.example.LoggingFilter");    reg.addMappingForUrlPatterns(null, false, "/");  }}

  实现类需要添加一个HandlesTypes注解,这个注解有一个value值,这个值是一个Class数组,包含了你想要处理的类,容器会扫描出所有匹配这个数组里面的类型的类(包含实现,扩展或者被注解的类),然后将这种类型作为onStartup的第一个参数传入。

?

?  Event Listeners(事件监听

?

  事件监听器提供ServletContext、HttpSession、ServletRequest对象的生命周期回调事件,监听器类实现一个接口,支持这些对象的状态变化的事件通知,通过注解@WebListener、在web.xml中声明,或通过注册一个ServletContext.addListener()方法来申明,监听器是不需要程序员额外明确编程化注册,或在初始化和恢复一个数据库连接去编程化的声明的一个servlet。可能有多个监听器类同时监听每一个事件类型,容器调用监听器时他们可能按指定的顺序监听每一个事件类型,应用程序关闭时以相反的顺序通知监听器。

  ServletContextListener监听容器的事件信息:

?

@WebListenerpublic class MyContextListener implements ServletContextListener {  @Override  public void contextInitialized(ServletContextEvent sce) {    ServletContext context = sce.getServletContext();    //. . .  }  @Override  public void contextDestroyed(ServletContextEvent sce) {  //. . .  }}

ServletContextAttributeListener监听上下文中属性的变化:

?

public class MyServletContextAttributeListener implements ServletContextAttributeListener {  @Override  public void attributeAdded(ServletContextAttributeEvent event) {    //. . . event.getName();    //. . . event.getValue();  }  @Override  public void attributeRemoved(ServletContextAttributeEvent event) {    //. . .  }  @Override  public void attributeReplaced(ServletContextAttributeEvent event) {    //. . .  }}

HttpSessionListener监听Session创建或销毁事件:

?

@WebListenerpublic class MySessionListener implements HttpSessionListener {  @Override  public void sessionCreated(HttpSessionEvent hse) {HttpSession session = hse.getSession();  //. . .  }  @Override  public void sessionDestroyed(HttpSessionEvent hse) {  //. . .  }}

  HttpSessionActivationListener用于监听Session钝化或激活事件:

?

public class MyHttpSessionActivationListener implements HttpSessionActivationListener {  @Override  public void sessionWillPassivate(HttpSessionEvent hse) {    // ... hse.getSession();  }  @Override  public void sessionDidActivate(HttpSessionEvent hse) {    // ...  }}

  HttpSessionAttributeListener用于监听Session中属性值变化事件:

?

public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {  @Override  public void attributeAdded(    HttpSessionBindingEvent event) {    HttpSession session = event.getSession();    //. . . event.getName();    //. . . event.getValue();  }  @Override  public void attributeRemoved(    HttpSessionBindingEvent event) {    //. . .  }  @Override  public void attributeReplaced(    HttpSessionBindingEvent event) {    //. . .  }}

  HttpSessionBindingListener用于监听对象绑定到Session或者解除绑定事件:

?

public class MyHttpSessionBindingListener implements HttpSessionBindingListener {  @Override  public void valueBound(HttpSessionBindingEvent event) {    HttpSession session = event.getSession();    //. . . event.getName();    //. . . event.getValue();  }  @Override  public void valueUnbound(HttpSessionBindingEvent event){    //. . .  }}

  ServletRequestListener监听Request状态:

?

@WebListenerpublic class MyRequestListener implements ServletRequestListener {  @Override  public void requestDestroyed(ServletRequestEvent sre) {    ServletRequest request = sre.getServletRequest();    //. . .  }  @Override  public void requestInitialized(ServletRequestEvent sre) {    //. . .  }}

  ServletRequestAttributeListener用于监听Request属性的变化,同时还有AsyncListener,用于管理例如完成、超时、出错等异步事件。

  在除了使用@WebListener和web.xml声明监听器外,他们还可以用使用ServletContext.addListener()方法编程方式定义,可以在ServletContainerInitializer.onStartup()或ServletContextListener.contextInitialized()方法中做到,当应用程序启动ServletContext的ServletContainerInitializer.onStartup()方法被调用:

?

public class MyInitializer implements ServletContainerInitializer {  public void onStartup(Set<Class<?>> clazz, ServletContext context) {    context.addListener("org.example.MyContextListener");  }}

?

  Asynchronous Support

?

  服务器资源是宝贵的应谨慎使用。考虑一个Servlet,它有一个JDBC连接,可从连接池中等待接收JMS消息或从文件系统中读取的资源,等待为一个“longrunning”的过程完全恢复阻塞的线程而等着坐着,什么都不做,这不是你使用服务器资源的最佳方式。这里服务器可以通过异步处理的控制(或线程)来执行长期运行的过程,其他任务完成后返回容器,当长期运行过程的响应返回时,或在长期运行的进程可能被分派到一个新的资源后,再用同一个线程请求继续处理。

  这是一个典型的应用,需要长时间运行过程的聊天应用程序,需要明确地启用一个servlet的异步行为,可以通过在@ WebServlet添加asyncSupported属性实现:

?

@WebServlet(urlPatterns="/async", asyncSupported=true)  public class MyAsyncServlet extends HttpServlet {  //. . .}

  它也可以在web.xml指定<async-supported>元素或ServletRegistration.setAsyncSupported(true)方式注册。异步处理就可以使用request的startasync()方法在一个单独的线程开始,这的方法返回一个AsyncContext,它代表了异步请求的执行上下文,异步请求可以通过调用AsyncContext.complete(explicit)或分发到另一个资源(隐式)去完成,容器完成异步请求的情况下然后调用后面的程序。让我们看一个长时间的进程完成的例子:

?

class MyAsyncService implements Runnable {  AsyncContext ac;  public MyAsyncService(AsyncContext ac) {    this.ac = ac;  }  @Override  public void run() {    //. . .    ac.complete();  }}

  此服务可能被调用doGet方法:

?

@Overrideprotected void doGet(HttpServletRequest request,HttpServletResponse response) {  AsyncContext ac = request.startAsync();  ac.addListener(new AsyncListener() {  public void onComplete(AsyncEvent event) throws IOException {    //. . .  }  public void onTimeout(AsyncEvent event) throws IOException {    //. . .  }  //. . .  });  ScheduledThreadPoolExexcutor executor =new ScheduledThreadPoolExexcutor(10);  executor.execut(new MyAsyncService(ac));}

  在这段代码中,该请求被设为异步模式。AsyncListener为请求处理完成、超时,和其他必要的行为注册监听事件,长时间运行的服务是在一个单独的线程中调用,并调用AsyncContext.complete(),发送请求处理完成的信号。一个请求可以从一个异步servlet发送去同步,但其他方式是非法的。异步行为可在Servlet、过滤器等使用。

?

  相关解决方案