以下内容是翻译自http://www.journaldev.com/1945/servletcontextlistener-servlet-listener-example

说明:web.xml的加载顺序是:【Context-Param】->【Listener】->【Filter】->【Servlet】,而同个类型之间的实际程序调用的时候的顺序是根据对应的Mapping的顺序进行调用。

为什么使用Servlet Listener?

我们知道使用ServletContext,我们可以创建一个具有所有其他servlet可以访问的应用范围的属性,但是我们可以在部署描述符(web.xml)中将ServletContext init参数初始化为String。如果我们的应用程序是面向数据库的,并且我们要在数据库连接的ServletContext中设置一个属性,该怎么办?如果应用程序具有单个入口点(用户登录),那么可以在第一个Servlet请求中执行,但是如果我们有多个入口点,那么在任何地方都会执行代码冗余。另外,如果数据库关闭或配置不正确,我们将不会知道,直到第一个客户端请求到达服务器。为了处理这些情况,Servlet API提供了Listener接口,我们可以实现和配置监听事件并执行某些操作。

事件(Event)是发生的事情,在Web应用程序世界中,事件可以是应用程序的初始化,销毁应用程序,从客户端请求,创建/销毁会话,会话中的属性修改等。

Servlet API提供了不同类型的侦听器接口,我们可以在web.xml中实现和配置,以便在特定事件发生时处理某些事件。例如,在上述情况下,我们可以为应用程序启动事件创建一个侦听器来读取上下文初始化参数并创建数据库连接,并将其设置为上下文属性以供其他资源使用。

Servlet Listener接口和事件(Event)对象

Servlet API为不同类型的事件提供了不同类型的侦听器。侦听器接口声明方法来处理一组类似的事件,例如我们有ServletContext Listener监听上下文的启动和关闭事件。侦听器界面中的每个方法都将事件对象作为输入。事件对象作为一个包装器,为侦听器提供特定的对象。

Servlet API提供以下事件对象:

  1. javax.servlet.AsyncEvent - 在ServletRequest(通过调用ServletRequest#startAsync或ServletRequest#startAsync(ServletRequest,ServletResponse))启动的异步操作已完成,超时或产生错误时触发的事件。
  2. javax.servlet.http.HttpSessionBindingEvent - 将此类型的事件发送到实现HttpSessionBindingListener的对象,当该对象从会话绑定或解除绑定时,或者发送到在web.xml中配置的HttpSessionAttributeListener,当绑定任何属性时,在会话中取消绑定或替换。会话通过对HttpSession.setAttribute的调用来绑定对象,并通过调用HttpSession.removeAttribute解除对象的绑定。当对象从会话中删除时,我们可以使用此事件进行清理活动。
  3. javax.servlet.http.HttpSessionEvent - 这是表示Web应用程序中会话更改的事件通知的类。
  4. javax.servlet.ServletContextAttributeEvent - 关于对Web应用程序的ServletContext的属性进行更改的通知的事件类。
  5. javax.servlet.ServletContextEvent - 这是关于Web应用程序的servlet上下文更改的通知的事件类。
  6. javax.servlet.ServletRequestEvent - 此类事件表示ServletRequest的生命周期事件。事件的源代码是这个Web应用程序的ServletContext。
  7. javax.servlet.ServletRequestAttributeEvent - 这是事件类,用于对应用程序中servlet请求的属性进行更改的通知。

Servlet API提供了以下监听器接口:

  1. javax.servlet.AsyncListener - 如果在添加了侦听器的ServletRequest上启动的异步操作已完成,超时或导致错误,将会通知侦听器。
  2. javax.servlet.ServletContextListener - 用于接收关于ServletContext生命周期更改的通知事件的接口。
  3. javax.servlet.ServletContextAttributeListener - 接收关于ServletContext属性更改的通知事件的接口。
  4. javax.servlet.ServletRequestListener - 用于接收关于进入和超出Web应用程序范围的请求的通知事件的接口。
  5. javax.servlet.ServletRequestAttributeListener - 接收关于ServletRequest属性更改的通知事件的接口。
  6. javax.servlet.http.HttpSessionListener - 接收关于HttpSession生命周期更改的通知事件的接口。
  7. javax.servlet.http.HttpSessionBindingListener - 使对象从会话绑定到绑定或从其绑定时被通知。
  8. javax.servlet.http.HttpSessionAttributeListener - 用于接收关于HttpSession属性更改的通知事件的接口。
  9. javax.servlet.http.HttpSessionActivationListener - 绑定到会话的对象可能会侦听容器事件,通知他们会话将被钝化,该会话将被激活。需要在VM或持久化会话之间迁移会话的容器来通知绑定到实现HttpSessionActivationListener的会话的所有属性。

Servlet Listener配置

我们可以使用@WebListener注解来声明一个类作为Listener,但是该类应该实现一个或多个Listener接口。

我们可以在web.xml中定义listener:

<listener>
<listener-class>
com.journaldev.listener.AppContextListener
</listener-class>
</listener>

Servlet Listener示例

让我们创建一个简单的Web应用程序来查看Servlet侦听器的操作。我们将在Eclipse ServletListenerExample中创建动态Web项目,这些项目结构将如下图所示。

web.xml:在部署描述符中,我将定义一些上下文初始化参数和监听器配置。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ServletListenerExample</display-name> <context-param>
<param-name>DBUSER</param-name>
<param-value>pankaj</param-value>
</context-param>
<context-param>
<param-name>DBPWD</param-name>
<param-value>password</param-value>
</context-param>
<context-param>
<param-name>DBURL</param-name>
<param-value>jdbc:mysql://localhost/mysql_db</param-value>
</context-param> <listener>
<listener-class>com.journaldev.listener.AppContextListener</listener-class>
</listener>
<listener>
<listener-class>com.journaldev.listener.AppContextAttributeListener</listener-class>
</listener>
<listener>
<listener-class>com.journaldev.listener.MySessionListener</listener-class>
</listener>
<listener>
<listener-class>com.journaldev.listener.MyServletRequestListener</listener-class>
</listener>
</web-app>

DBConnectionManager:这是数据库连接的类,为了简单起见,我没有为实际的数据库连接提供代码。我们将这个对象设置为servlet上下文的属性。

package com.journaldev.db;

import java.sql.Connection;

public class DBConnectionManager {

    private String dbURL;
private String user;
private String password;
private Connection con; public DBConnectionManager(String url, String u, String p){
this.dbURL=url;
this.user=u;
this.password=p;
//create db connection now } public Connection getConnection(){
return this.con;
} public void closeConnection(){
//close DB connection here
}
}

MyServlet:一个简单的servlet类,我将使用会话,属性等。

package com.journaldev.servlet;

import java.io.IOException;
import java.io.PrintWriter; import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; @WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext ctx = request.getServletContext();
ctx.setAttribute("User", "Pankaj");
String user = (String) ctx.getAttribute("User");
ctx.removeAttribute("User"); HttpSession session = request.getSession();
session.invalidate(); PrintWriter out = response.getWriter();
out.write("Hi "+user);
} }

现在我们将实现监听器类,我为常用的监听器提供了示例侦听器类 - ServletContextListener,ServletContextAttributeListener,ServletRequestListener和HttpSessionListener。

ServletContextListener

我们将读取servlet context init参数来创建DBConnectionManager对象,并将其设置为ServletContext对象的属性。

package com.journaldev.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener; import com.journaldev.db.DBConnectionManager; @WebListener
public class AppContextListener implements ServletContextListener { public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext ctx = servletContextEvent.getServletContext(); String url = ctx.getInitParameter("DBURL");
String u = ctx.getInitParameter("DBUSER");
String p = ctx.getInitParameter("DBPWD"); //create database connection from init parameters and set it to context
DBConnectionManager dbManager = new DBConnectionManager(url, u, p);
ctx.setAttribute("DBManager", dbManager);
System.out.println("Database connection initialized for Application.");
} public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext ctx = servletContextEvent.getServletContext();
DBConnectionManager dbManager = (DBConnectionManager) ctx.getAttribute("DBManager");
dbManager.closeConnection();
System.out.println("Database connection closed for Application."); } }

ServletContextAttributeListener

在servlet上下文中添加,删除或替换属性时,记录事件的简单实现。

package com.journaldev.listener;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener; @WebListener
public class AppContextAttributeListener implements ServletContextAttributeListener { public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext attribute added::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}");
} public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext attribute replaced::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}");
} public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext attribute removed::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}");
} }

HttpSessionListener

创建或销毁会话时记录事件的简单实现。

package com.journaldev.listener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener; @WebListener
public class MySessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent sessionEvent) {
System.out.println("Session Created:: ID="+sessionEvent.getSession().getId());
} public void sessionDestroyed(HttpSessionEvent sessionEvent) {
System.out.println("Session Destroyed:: ID="+sessionEvent.getSession().getId());
} }

ServletRequestListener

ServletRequestListener接口的简单实现,用于在请求初始化和销毁​​时记录ServletRequest IP地址。

package com.journaldev.listener;

import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener; @WebListener
public class MyServletRequestListener implements ServletRequestListener { public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
ServletRequest servletRequest = servletRequestEvent.getServletRequest();
System.out.println("ServletRequest destroyed. Remote IP="+servletRequest.getRemoteAddr());
} public void requestInitialized(ServletRequestEvent servletRequestEvent) {
ServletRequest servletRequest = servletRequestEvent.getServletRequest();
System.out.println("ServletRequest initialized. Remote IP="+servletRequest.getRemoteAddr());
} }

现在,当我们将使用URL部署我们的应用程序并在浏览器中访问MyServlet时http://localhost:8080/ServletListenerExample/MyServlet,我们将在服务器日志文件中看到以下日志。

ServletContext attribute added::{DBManager,com.journaldev.db.DBConnectionManager@4def3d1b}
Database connection initialized for Application.
ServletContext attribute added::{org.apache.jasper.compiler.TldLocationsCache,org.apache.jasper.compiler.TldLocationsCache@1594df96} ServletRequest initialized. Remote IP=0:0:0:0:0:0:0:1%0
ServletContext attribute added::{User,Pankaj}
ServletContext attribute removed::{User,Pankaj}
Session Created:: ID=8805E7AE4CCCF98AFD60142A6B300CD6
Session Destroyed:: ID=8805E7AE4CCCF98AFD60142A6B300CD6
ServletRequest destroyed. Remote IP=0:0:0:0:0:0:0:1%0 ServletRequest initialized. Remote IP=0:0:0:0:0:0:0:1%0
ServletContext attribute added::{User,Pankaj}
ServletContext attribute removed::{User,Pankaj}
Session Created:: ID=88A7A1388AB96F611840886012A4475F
Session Destroyed:: ID=88A7A1388AB96F611840886012A4475F
ServletRequest destroyed. Remote IP=0:0:0:0:0:0:0:1%0 Database connection closed for Application.

注意日志的顺序,它按照执行的顺序。当您关闭应用程序或关闭容器时,将显示最后一个日志。

这是Servlet中的所有的监听器。

测试工程:https://github.com/easonjim/5_java_example/tree/master/servletbasics/test20

Servlet监听器(Listener)实例的更多相关文章

  1. servlet监听器Listener(理论+例子)

    Listener采用了观察者模式(24种模式之一),Listener是servlet的监听器,他可以监听客户端的请求.服务器端的操作等, 通过监听器,可以自动激发一些操作.比如:监听在线用户数量 当增 ...

  2. java之Servlet监听器Listener

    常用应用场景:单点登录.统计在线人数 一.简介 (一)概述 1.Listener 用于监听 java web程序中的事件,例如创建.修改.删除Session.request.context等,并触发响 ...

  3. Servlet 监听器Listener详解

    转自:http://blog.csdn.net/u012228718/article/details/41730799 一.简介 (一)概述 1.Listener 用于监听 Javaweb程序中的事件 ...

  4. Java进阶(十三)servlet监听器

    servlet监听器 Listener是Servlet的监听器,它可以监听客户端的请求.服务端的操作等.通过监听器,可以自动激发一些操作,比如监听在线的用户的数量.当 增加一个HttpSession时 ...

  5. [原创]java WEB学习笔记47:Servlet 监听器简介, ServletContext(Application 对象), HttpSession (Session 对象), HttpServletRequest (request 对象) 监听器,利用listener理解 三个对象的生命周期

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  6. Servlet的监听器Listener

    Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是 随web应用的启动而启动,只初始化一次,随web ...

  7. servlet/filter/listener/interceptor区别与联系

    转自:http://www.cnblogs.com/doit8791/p/4209442.html servlet.filter.listener是配置到web.xml中(web.xml 的加载顺序是 ...

  8. Java中Filter、Servlet、Listener的学习

    1.Filter的功能filter功能,它使用户可以改变一个 request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个reques ...

  9. 转 Java中Filter、Servlet、Listener的学习

      1.Filter的功能filter功能,它使用户可以改变一个 request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个requ ...

  10. 过滤器Filter与监听器Listener

    过滤器Filter 过滤器也是一种servlet   它也可以对用户的请求进行处理  , 但是他所做的处理,只是一些轻量级的处理.Fileter就好像jsp页面与servlet之间的一道关卡,如果这个 ...

随机推荐

  1. 树形DP Gym 100496H House of Representatives

    题目传送门 /* 题意:寻找一个根节点,求min f(u) = ∑ρ(v, u) * p(v).ρ(v, u)是u到v的距离,p(v)是v点的权值 树形DP:先从1出发遍历第一次,sum[u]计算u到 ...

  2. 日期时间选择器插件flatpickr

    前言:在网页上需要输入时间的时候,我们可以用HTML5的inputl中的date类型.但是如下入所示,有些浏览器不支持.flatpickr这个小插件可以解决这个问题. 1.flatpickr日期时间选 ...

  3. Spring: (一) -- 春雨润物之 核心IOC

    作为一个Java人,想必都或多或少的了解过Spring.对于其优势也能道个一二,诸如方便解耦.支持AOP编程.支持声明式事务.方便测试等等.Spring也不仅仅局限于服务器端开发,它可以做非常多的事情 ...

  4. Unity笔记(3)自学第三天

    学习记录: 脚本使用:

  5. 华硕(ASUS)X554LP笔记本重装win7后网卡和USB驱动问题的解决

    以前在其它笔记本上采用U盘克隆安装winxp系统非常顺利,各种硬件驱动能自动识别并安装. 手上有一台别人的华硕(ASUS)X554LP笔记本,原装win8.1,用不惯,想装个win7旗舰版. 照例去系 ...

  6. Mysql5.7多源复制,过滤复制一段时间后增加复制一个库的实现方法

    多源复制如果是整个实例级别的复制,那不存在下面描述的情况. 如果是对其中一个或多个主实例都是过滤复制,并且运行一段时间后,想在这个源上再增加一个库怎么实现?   主1:192.168.1.10 330 ...

  7. SQL SERVER 执行计划各字段注释

    SET SHOWPLAN_ALL使 Microsoft® SQL Server™ 不执行 Transact-SQL 语句.相反,SQL Server 返回有关语句执行方式和语句预计所需资源的详细信息. ...

  8. jstree中json data 的生成

       jstree中json data 的生成 jstree官网上给出的json数据格式是这样的: <span style="font-size:14px;">// A ...

  9. MySQL学习笔记(十二)__连接查询(一)

    连接查询含义:又称多表查询,当查询的字段来自多个表时,就会用到连接查询 笛卡尔乘积现象:表1 有 m 行,表2 有 n 行,结果 = m*n 行发生原因:没有有效的连接条件如何避免:添加有效的连接条件 ...

  10. mysql数据转sql server

    创建一个mysql的ODBC数据源,在sql server中“任务”-“导入数据” -“选择创建的ODBC数据源” 然后填写服务器 登录名.密码,需要导入的数据库表什么的