監聽器入門看這篇就夠了


什么是監聽器

監聽器就是一個實現特定接口的普通java程序,這個程序專門用於監聽另一個java對象的方法調用或屬性改變,當被監聽對象發生上述事件后,監聽器某個方法將立即被執行。。

為什么我們要使用監聽器?

監聽器可以用來檢測網站的在線人數,統計網站的訪問量等等

監聽器組件

監聽器涉及三個組件:事件源,事件對象,事件監聽器

當事件源發生某個動作的時候,它會調用事件監聽器的方法,並在調用事件監聽器方法的時候把事件對象傳遞進去。

我們在監聽器中就可以通過事件對象獲取得到事件源,從而對事件源進行操作!

這里寫圖片描述


模擬監聽器

既然上面已經說了監聽器的概念了,監聽器涉及三個組件:事件源,事件對象,事件監聽器。

我們就寫一個對象,被監聽器監聽

監聽器

監聽器定義為接口,監聽的方法需要事件對象傳遞進來,從而在監聽器上通過事件對象獲取得到事件源,對事件源進行修改


	/**
	 * 事件監聽器
	 *
	 * 監聽Person事件源的eat和sleep方法
	 */
	interface PersonListener{
	
	    void doEat(Event event);
	    void doSleep(Event event);
	}

事件源

事件源是一個Person類,它有eat和sleep()方法。

事件源需要注冊監聽器(即在事件源上關聯監聽器對象)

如果觸發了eat或sleep()方法的時候,會調用監聽器的方法,並將事件對象傳遞進去



	/**
	 *
	 * 事件源Person
	 *
	 * 事件源要提供方法注冊監聽器(即在事件源上關聯監聽器對象)
	 */
	
	class Person {
	
	    //在成員變量定義一個監聽器對象
	    private PersonListener personListener ;
	    
	    //在事件源中定義兩個方法
	    public void Eat() {
	        
	        //當事件源調用了Eat方法時,應該觸發監聽器的方法,調用監聽器的方法並把事件對象傳遞進去
	        personListener.doEat(new Event(this));
	    }
	
	    public void sleep() {
	
	        //當事件源調用了Eat方法時,應該觸發監聽器的方法,調用監聽器的方法並把事件對象傳遞進去
	        personListener.doSleep(new Event(this));
	    }
	
	    //注冊監聽器,該類沒有監聽器對象啊,那么就傳遞進來吧。
	    public void registerLister(PersonListener personListener) {
	        this.personListener = personListener;
	    }
	
	}


事件對象

事件對象封裝了事件源。

監聽器可以從事件對象上獲取得到事件源的對象(信息)




	/**
	 * 事件對象Even
	 *
	 * 事件對象封裝了事件源
	 *
	 * 在監聽器上能夠通過事件對象獲取得到事件源
	 *
	 *
	 */
	class Event{
	    private Person person;
	
	    public Event() {
	    }
	
	    public Event(Person person) {
	        this.person = person;
	    }
	
	    public Person getResource() {
	        return person;
	    }
	
	}

測試


    public static void main(String[] args) {

        Person person = new Person();

        //注冊監聽器()
        person.registerLister(new PersonListener() {
            @Override
            public void doEat(Event event) {
                Person person1 = event.getResource();
                System.out.println(person1 + "正在吃飯呢!");
            }

            @Override
            public void doSleep(Event event) {
                Person person1 = event.getResource();
                System.out.println(person1 + "正在睡覺呢!");
            }
        });


        //當調用eat方法時,觸發事件,將事件對象傳遞給監聽器,最后監聽器獲得事件源,對事件源進行操作
        person.Eat();
    }


這里寫圖片描述

  • 事件源:擁有事件
  • 監聽器:監聽事件源所擁有的事件(帶事件對象參數的)
  • 事件對象:事件對象封裝了事件源對象
    • 事件源要與監聽器有關系,就得注冊監聽器【提供方法得到監聽器對象】
    • 觸發事件源的事件,實際會提交給監聽器對象處理,並且把事件對象傳遞過去給監聽器

Servle監聽器

在Servlet規范中定義了多種類型的監聽器,它們用於監聽的事件源分別 ServletContext, HttpSession和ServletRequest這三個域對象

和其它事件監聽器略有不同的是,servlet監聽器的注冊不是直接注冊在事件源上,而是由WEB容器負責注冊,開發人員只需在web.xml文件中使用<listener>標簽配置好監聽器

監聽對象的創建和銷毀

HttpSessionListener、ServletContextListener、ServletRequestListener分別監控着Session、Context、Request對象的創建和銷毀

  • HttpSessionListener(可以用來收集在線者信息)
  • ServletContextListener(可以獲取web.xml里面的參數配置)
  • ServletRequestListener

測試



public class Listener1 implements ServletContextListener,
        HttpSessionListener, ServletRequestListener {

    // Public constructor is required by servlet spec
    public Listener1() {
    }
    
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("容器創建了");
    }

    public void contextDestroyed(ServletContextEvent sce) {

        System.out.println("容器銷毀了");
    }


    public void sessionCreated(HttpSessionEvent se) {

        System.out.println("Session創建了");
    }

    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("Session銷毀了");
    }


    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        
    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {

    }
}

  • 監聽器監聽到ServletContext的初始化了,Session的創建和ServletContext的銷毀。(服務器停掉,不代表Session就被銷毀了。Session的創建是在內存中的,所以沒看到Session被銷毀了)

這里寫圖片描述


監聽對象屬性變化

ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener分別監聽着Context、Session、Request對象屬性的變化

這三個接口中都定義了三個方法來處理被監聽對象中的屬性的增加,刪除和替換的事件,同一個事件在這三個接口中對應的方法名稱完全相同,只是接受的參數類型不同

  • attributeAdded()
  • attributeRemoved()
  • attributeReplaced()

測試

這里我只演示Context對象,其他對象都是以此類推的,就不一一測試了

  • 實現ServletContextAttributeListener接口。


	public class Listener1 implements ServletContextAttributeListener {
	
	    @Override
	    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
	        System.out.println("Context對象增加了屬性");
	    }
	
	    @Override
	    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
	        System.out.println("Context對象刪除了屬性");
	
	    }
	
	    @Override
	    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
	        System.out.println("Context對象替換了屬性");
	
	    }
	}



  • 測試的Servlet


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        ServletContext context = this.getServletContext();

        context.setAttribute("aa", "123");
        context.setAttribute("aa", "234");
        context.removeAttribute("aa");
        
    }

這里寫圖片描述


監聽Session內的對象

除了上面的6種Listener,還有兩種Linstener監聽Session內的對象,分別是HttpSessionBindingListener和HttpSessionActivationListener,實現這兩個接口並不需要在web.xml文件中注冊

  • 實現HttpSessionBindingListener接口,**JavaBean 對象可以感知自己被綁定到 Session 中和從 Session 中刪除的事件【和HttpSessionAttributeListener的作用是差不多的】 **
  • 實現HttpSessionActivationListener接口,JavaBean 對象可以感知自己被活化和鈍化的事件(當服務器關閉時,會將Session的內容保存在硬盤上【鈍化】,當服務器開啟時,會將Session的內容在硬盤式重新加載【活化】) 。。

想要測試出Session的硬化和鈍化,需要修改Tomcat的配置的。在META-INF下的context.xml文件中添加下面的代碼:


<Context>
  <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
  <Store className="org.apache.catalina.session.FileStore" directory="zhongfucheng"/>
  </Manager>
</Context>

這里寫圖片描述

測試

  • 監聽器和事件源


/*
* 由於涉及到了將內存的Session鈍化到硬盤和用硬盤活化到內存中,所以需要實現Serializable接口
*
* 該監聽器是不需要在web.xml文件中配置的。但監聽器要在事件源上實現接口
* 也就是說,直接用一個類實現HttpSessionBindingListener和HttpSessionActivationListener接口是監聽不到Session內對象的變化的。
* 因為它們是感知自己在Session中的變化!
* */
public class User implements HttpSessionBindingListener,HttpSessionActivationListener,Serializable {

    private String username ;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }


    @Override
    public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) {

        HttpSession httpSession = httpSessionEvent.getSession();

        System.out.println("鈍化了");

    }

    @Override
    public void sessionDidActivate(HttpSessionEvent httpSessionEvent) {
        HttpSession httpSession = httpSessionEvent.getSession();
        System.out.println("活化了");

    }
    @Override
    public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {

        System.out.println("綁定了對象");
    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("解除了對象");

    }
}
  • 測試代碼


        User user = new User();
        request.getSession().setAttribute("aaa", user);
        request.getSession().removeAttribute("aaa");
  • 效果:

這里寫圖片描述


如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,可以關注微信公眾號:Java3y


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM