監聽器就是一個實現特定接口的普通java程序,這個程序專門用於監聽另外一個java對象的方法調用或屬性改變,當被監聽對象發生上述事件後,監聽器某個方法將當即被執行。java
監聽器能夠用來檢測網站的在線人數,統計網站的訪問量等等!web
監聽器涉及三個組件:事件源,事件對象,事件監聽器apache
當事件源發生某個動做的時候,它會調用事件監聽器的方法,並在調用事件監聽器方法的時候把事件對象傳遞進去。服務器
咱們在監聽器中就能夠經過事件對象獲取獲得事件源,從而對事件源進行操做!markdown
既然上面已經說了監聽器的概念了,監聽器涉及三個組件:事件源,事件對象,事件監聽器。session
咱們就寫一個對象,被監聽器監聽ide
監聽器定義爲接口,監聽的方法須要事件對象傳遞進來,從而在監聽器上經過事件對象獲取獲得事件源,對事件源進行修改!測試
/** * 事件監聽器 * * 監聽Person事件源的eat和sleep方法 */ interface PersonListener{ void doEat(Event event); void doSleep(Event event); }
事件源是一個Person類,它有eat和sleep()方法。網站
事件源須要註冊監聽器(即在事件源上關聯監聽器對象)ui
若是觸發了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(); }
在Servlet規範中定義了多種類型的監聽器,它們用於監聽的事件源分別 ServletContext, HttpSession和ServletRequest這三個域對象
和其它事件監聽器略有不一樣的是,servlet監聽器的註冊不是直接註冊在事件源上,而是由WEB容器負責註冊,開發人員只需在web.xml文件中使用<listener>
標籤配置好監聽器,
HttpSessionListener、ServletContextListener、ServletRequestListener分別監控着Session、Context、Request對象的建立和銷燬
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) { } }
ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener分別監聽着Context、Session、Request對象屬性的變化
這三個接口中都定義了三個方法來處理被監聽對象中的屬性的增長,刪除和替換的事件,同一個事件在這三個接口中對應的方法名稱徹底相同,只是接受的參數類型不一樣。
這裏我只演示Context對象,其餘對象都是以此類推的,就不一一測試了。
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對象替換了屬性"); } }
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"); }
除了上面的6種Listener,還有兩種Linstener監聽Session內的對象,分別是HttpSessionBindingListener和HttpSessionActivationListener,實現這兩個接口並不須要在web.xml文件中註冊
想要測試出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");