Servlet監聽器(Listener)實例

如下內容是翻譯自http://www.journaldev.com/1945/servletcontextlistener-servlet-listener-examplejava

說明: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提供如下事件對象:瀏覽器

  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

相關文章
相關標籤/搜索