监听器原理与案例分析
1.普通监听器
监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
监听器典型案例:监听window窗口的事件监听器
分别用两个方法来实现关闭window的窗体;一个是编写一个继承了windowListener接口的关闭类然后注册这个类的监听;另一个是直接用适配器匿名内部类。这里有一点要注意:System.exit(0)表示关闭整个应用;Frame.dispose()表示关闭该窗口。具体案例如下:
package com.csdn.windowlistener; import java.awt.Frame; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; publicclass Demo { publicstaticvoid main(String[] args) { Frame f = new Frame(); f.setSize(300,300); f.setVisible(true); //f.addWindowListener(new MyWindowLitener()); //另一种方法是匿名类适配器 f.addWindowListener(new WindowAdapter() { @Override publicvoid windowClosing(WindowEvent e) { Frame f = (Frame) e.getSource(); f.dispose(); System.out.println("关闭了!"); } }); } } //一种方法是实现WindowListener接口 class MyWindowLitenerimplements WindowListener{ @Override publicvoid windowActivated(WindowEvent e) { } @Override publicvoid windowClosed(WindowEvent e) { } @Override publicvoid windowClosing(WindowEvent e) { Frame f = (Frame) e.getSource(); f.dispose(); System.out.println("关闭了!"); } @Override publicvoid windowDeactivated(WindowEvent e) { } @Override publicvoid windowDeiconified(WindowEvent e) { } @Override publicvoid windowIconified(WindowEvent e) { } @Override publicvoid windowOpened(WindowEvent e) { } }
2.Servle监听器
l 在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext, HttpSession 和 ServletRequest 这三个域对象。
l Servlet规范针对这三个对象上的操作,又把这多种类型的监听器划分为三种类型。
• 监听三个域对象创建和销毁的事件监听器
• 监听域对象中属性的增加和删除的事件监听器
• 监听绑定到 HttpSession 域中的某个对象的状态的事件监听器。(查看API文档)
3.分条介绍
监听servletContext域对象创建和销毁
ServletContextListener 接口用于监听 ServletContext 对象的创建和销毁事件。当 ServletContext 对象被创建时,激发contextInitialized (ServletContextEvent sce)方法
ServletContext 对象被销毁时,激发contextDestroyed(ServletContextEvent sce)方法。
servletContext域对象何时创建和销毁:创建:服务器启动针对每一个web应用创建servletcontext销毁:服务器关闭前先关闭代表每一个web应用的servletContext
监听HttpSession域对象创建和销毁
HttpSessionListener接口用于监听HttpSession创建和销毁。建一个Session时,sessionCreated(HttpSessionEvent se) 方法将会被调用。销毁一个Session时,sessionDestroyed (HttpSessionEvent se) 方法将会被调用。
Session域对象创建和销毁的时机创建:用户每一次访问时,服务器创建session,访问时调用getSession()方法才创建,否则不创建,比如你开一个浏览器窗口调用一个静态页面html时没有创建session,所以没有不调用改方法;但是执行一个jsp时创建,因为jsp要在tomcat后台翻译成一个servlet,翻译的过程中默认的是创建session,如果直接在jsp页面设置session=false后则不再创建session,这两点要特别注意。销毁:如果用户的session 30分钟没有使用,服务器就会销毁session,我们在web.xml里面也可以配置session失效时间
监听HttpRequest域对象创建和销毁
ServletRequestListener 接口用于监听ServletRequest 对象的创建和销毁。Request 对象被创建时,监听器的requestInitialized方法将会被调用。Request对象被销毁时,监听器的requestDestroyed方法将会被调用。可以自己实验在浏览器窗口中多次刷新访问servlet,看request对象的创建和销毁,并写一个servlet,然后用sendRedirect、forward方式跳转到其它servlet,查看request对象的创建和消耗)
servletRequest域对象创建和销毁的时机:创建:用户每一次访问,都会创建一个reqeust;销毁:当前访问结束,request对象就会销毁
4.监听三个域对象属性变化
Servlet规范定义了监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信息事件的监听器。这三个监听器接口分别是ServletContextAttributeListener, HttpSessionAttributeListenerServletRequestAttributeListener
这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。
l attributeAdded 方法
当向被监听器对象中增加一个属性时,web容器就调用事件监听器的 attributeAdded 方法进行相应,这个方法接受一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象
l 各个域属性监听器中的完整语法定义为:
public void attributeAdded(ServletContextAttributeEvent scae)
public void attributeAdded (HttpSessionBindingEvent hsbe) public void attributeAdded (ServletRequestAttributeEvent srae)
l attributeRemoved 方法
当删除被监听对象中的一个属性时,web 容器调用事件监听器的这个方法进行相应
l 各个域属性监听器中的完整语法定义为:
public void attributeRemoved(ServletContextAttributeEvent scae)
public void attributeRemoved (HttpSessionBindingEvent hsbe)
public void attributeRemoved (ServletRequestAttributeEvent srae)
l attributeReplaced 方法
当监听器的域对象中的某个属性被替换时,web容器调用事件监听器的这个方法进行相应
l 各个域属性监听器中的完整语法定义为:
public void attributeReplaced(ServletContextAttributeEvent scae)
public void attributeReplaced (HttpSessionBindingEvent hsbe)
public void attributeReplaced (ServletRequestAttributeEvent srae)
5编写 Servlet监听器
和编写其它事件监听器一样,编写servlet监听器也需要实现一个特定的接口,并针对相应动作覆盖接口中的相应方法。和其它事件监听器略有不同的是,servlet监听器的注册不是直接注册在事件源上,而是由WEB容器负责注册,开发人员只需在web.xml文件中使用<listener>标签配置好监听器,web容器就会自动把监听器注册到事件源中。一个 web.xml 文件中可以配置多个 Servlet 事件监听器,web 服务器按照它们在 web.xml 文件中的注册顺序来加载和注册这些 Serlvet 事件监听器。
l Servlet监听器在开发中的应用案例一:统计当前在线人数
package com.csn.web.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { ServletContext sc = se.getSession().getServletContext(); Integer count = (Integer) sc.getAttribute("count"); if(count==null){ count = 1; }else{ count++; } sc.setAttribute("count",count); } @Override public void sessionDestroyed(HttpSessionEvent se) { ServletContext sc = se.getSession().getServletContext(); Integer count = (Integer) sc.getAttribute("count"); count--; sc.setAttribute("count",count); } }
l Servlet监听器在开发中的应用案例二示登陆用户列表,并实现踢人功能。
注:下面web应用只简单的列出主要类和监听器;主要完成一个论坛管理员踢人的功能;整个web应用源码项目本人已免费上传到资源,有兴趣的可以去本人资源区下载
主要类监听器:SessionLister.java package com.csdn.web.listener; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import com.csdn.domain.User; public class SessionListener implements HttpSessionAttributeListener { @Override public void attributeAdded(HttpSessionBindingEvent se) { Object obj = se.getValue(); if(obj instanceof User){ User user = (User) obj; HttpSession session = se.getSession(); Map map = (Map) session.getServletContext().getAttribute("map"); if(map==null){ map = new HashMap(); session.getServletContext().setAttribute("map",map); } map.put(user.getUsername(),session); } } @Override public void attributeRemoved(HttpSessionBindingEvent se) { } @Override public void attributeReplaced(HttpSessionBindingEvent se) { } } 主要servlet(踢人类) KickUserServlet.java package com.csdn.web.servlet; import java.io.IOException; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class KickUserServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); username = new String(username.getBytes("iso8859-1"),"UTF-8"); Map map = (Map)this.getServletContext().getAttribute("map"); HttpSession session = (HttpSession) map.get(username); if(session != null){ session.invalidate(); //移除session map.remove(username); } request.getRequestDispatcher("/listUser.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }