如下内容是翻译自http://www.journaldev.com/1945/servletcontextlistener-servlet-listener-example:java
说明:web.xml的加载顺序是:【Context-Param】->【Listener】->【Filter】->【Servlet】,而同个类型之间的实际程序调用的时候的顺序是根据对应的Mapping的顺序进行调用。mysql
为何使用Servlet Listener?git
咱们知道使用ServletContext
,咱们能够建立一个具备全部其余servlet能够访问的应用范围的属性,可是咱们能够在部署描述符(web.xml)中将ServletContext init参数初始化为String。若是咱们的应用程序是面向数据库的,而且咱们要在数据库链接的ServletContext中设置一个属性,该怎么办?若是应用程序具备单个入口点(用户登陆),那么能够在第一个Servlet请求中执行,可是若是咱们有多个入口点,那么在任何地方都会执行代码冗余。另外,若是数据库关闭或配置不正确,咱们将不会知道,直到第一个客户端请求到达服务器。为了处理这些状况,Servlet API提供了Listener接口,咱们能够实现和配置监听事件并执行某些操做。github
事件(Event)是发生的事情,在Web应用程序世界中,事件能够是应用程序的初始化,销毁应用程序,从客户端请求,建立/销毁会话,会话中的属性修改等。web
Servlet API提供了不一样类型的侦听器接口,咱们能够在web.xml中实现和配置,以便在特定事件发生时处理某些事件。例如,在上述状况下,咱们能够为应用程序启动事件建立一个侦听器来读取上下文初始化参数并建立数据库链接,并将其设置为上下文属性以供其余资源使用。sql
Servlet Listener接口和事件(Event)对象数据库
Servlet API为不一样类型的事件提供了不一样类型的侦听器。侦听器接口声明方法来处理一组相似的事件,例如咱们有ServletContext Listener监听上下文的启动和关闭事件。侦听器界面中的每一个方法都将事件对象做为输入。事件对象做为一个包装器,为侦听器提供特定的对象。apache
Servlet API提供如下事件对象:浏览器
Servlet API提供了如下监听器接口:服务器
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