Java 监听器(Listener)的工作原理和代码演示
Java Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。
首先来看一下ServletContextListener接口的源代码:
public abstract interface ServletContextListener extends EventListener{ public abstract void contextInitialized(ServletContextEvent paramServletContextEvent); public abstract void contextDestroyed(ServletContextEvent paramServletContextEvent); }
示例1: 连接数据库池
利用监听器对数据库连接池DataSource的初始化演示它的使用:ListenerTest.java
package com.mimvp.listen; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.apache.commons.dbcp.BasicDataSource; /** * @author mimvp.com */ public class ListenerTest implements ServletContextListener { // 构造函数 public ListenerTest() { // TODO Auto-generated constructor stub } // 应用监听器的销毁方法 @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { ServletContext servletContext = servletContextEvent.getServletContext(); // 在整个web应用销毁之前调用,将所有应用空间设置的内容清空 servletContext.removeAttribute("dataSource"); System.out.println("销毁工作完成!"); } // 应用监听器的初始化方法 @Override public void contextInitialized(ServletContextEvent servletContextEvent) { // 通过事件获取整个应用空间,在整个web应用下面启动时做一些初始化的内容添加工作 ServletContext servletContext = servletContextEvent.getServletContext(); // 设置一些基本的内容,比如一些参数或一些固定对象 // 创建DataSource对象、连接池技术 DBCP BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3306/"); basicDataSource.setUsername("root"); basicDataSource.setPassword("123456"); basicDataSource.setMaxActive(10); // 最大连接数 basicDataSource.setMaxIdle(5); // 最大管理数 basicDataSource.setMaxWait(60); // 最大等待时间 // 将 DataSource 放入ServletContext空间里,供整个web应用获取数据库连接 servletContext.setAttribute("dataSource", basicDataSource); System.out.println("应用监听器初始化工作完成...."); System.out.println("已创建 dataSource"); } }
web.xml 配置内容如下:
vim /com.mimvp.homer/src/main/webapp/WEB-INF/web.xml
<listener> <listener-class>com.mimvp.listen.ListenerTest</listener-class> </listener>
配置好后,以后在web应用中就可以通过ServletContext取得BasicDataSource对象,从而获取与数据库的连接,提高性能,方便使用。
启动项目后,在Tomcat服务器打印的日志如下:
[org.springframework.web.context.ContextLoader] - Root WebApplicationContext: initialization started
[org.springframework.web.context.support.XmlWebApplicationContext] - Refreshing Root WebApplicationContext: startup date [Fri Apr 28 11:23:38 CST 2017]; root of context hierarchy
[org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from class path resource [spring-mybatis.xml]
[org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] - Loading properties file from class path resource [jdbc.properties]
[org.springframework.web.context.ContextLoader] - Root WebApplicationContext: initialization completed in 864 ms
应用监听器初始化工作完成....
已创建 dataSource
示例2: 获取项目路径
package com.mimvp.listen; import java.io.File; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class ListenerTest2 implements ServletContextListener { public ListenerTest2() { // TODO Auto-generated constructor stub } // 销毁监听器 @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("dataDestroyed: " + servletContextEvent.getServletContext()); } // 初始化监听器 @Override public void contextInitialized(ServletContextEvent servletContextEvent) { try { String basePath = servletContextEvent.getServletContext().getRealPath("/"); System.out.println("basePath: " + basePath); // basePath: E:\myPro\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\com.mimvp.homer\ if(!(basePath.endsWith(File.separator))) { basePath = basePath + File.separator; } basePath = basePath + "WEB-INF" + File.separator + "classes" + File.separator; System.out.println("basePath2: " + basePath); // basePath2: E:\myPro\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\com.mimvp.homer\WEB-INF\classes\ } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } }
示例3: Session 监听
package com.mimvp.listen; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; class OnlineUserMonitorClient { public OnlineUserMonitorClient(){ } public boolean afterSessionDestroyed(HttpSession httpSession) { httpSession.removeAttribute("onlineUserMonitorClient"); return true; } } public class ListenerUser implements HttpSessionListener { protected final Log log = LogFactory.getLog(super.getClass()); // 构造函数 public ListenerUser() { // TODO Auto-generated constructor stub } // 创建Session @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { this.log.error("Session create id = " + httpSessionEvent.getSession().getId()); } // 销毁Session @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { this.log.error("Session destory id = " + httpSessionEvent.getSession().getId()); HttpSession httpSession = httpSessionEvent.getSession(); ServletContext servletContext = httpSession.getServletContext(); ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext); OnlineUserMonitorClient client = (OnlineUserMonitorClient)context.getBean("onlineUserMonitorClient"); client.afterSessionDestroyed(httpSession); } }
监听器在实际项目中的应用,监听器在java web中应用的较多,
比如:统计当前在线人数、自定义session扫描器。
应用1:统计当前在线人数
package com.mimvp.listen; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class SessionListener implements HttpSessionListener { public static int TOTAL_ONLINE_USERS = 0; public SessionListener() { // TODO Auto-generated constructor stub } @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { ServletContext servletContext = httpSessionEvent.getSession().getServletContext(); TOTAL_ONLINE_USERS = (Integer)servletContext.getAttribute("TOTAL_ONLINE_USERS"); // 如果用户退出,TOTAL_ONLINE_USERS自加1 if(0 == TOTAL_ONLINE_USERS){ servletContext.setAttribute("TOTAL_ONLINE_USERS", 1); } else { TOTAL_ONLINE_USERS++; servletContext.setAttribute("TOTAL_ONLINE_USERS", TOTAL_ONLINE_USERS); } } @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { ServletContext servletContext = httpSessionEvent.getSession().getServletContext(); TOTAL_ONLINE_USERS = (Integer)servletContext.getAttribute("TOTAL_ONLINE_USERS"); // 如果用户退出,TOTAL_ONLINE_USERS自减1 if(0 == TOTAL_ONLINE_USERS){ servletContext.setAttribute("TOTAL_ONLINE_USERS", 1); } else { TOTAL_ONLINE_USERS--; servletContext.setAttribute("TOTAL_ONLINE_USERS", TOTAL_ONLINE_USERS); } } }
应用2:自定义session扫描器
SessionScanerListener.java
package com.mimvp.listen; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Timer; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * 当网站用户量增加时,session占用的内存会越来越大,这时session的管理,将会是一项很大的系统开销, * 为了高效的管理session,可以写一个监听器,定期清理掉过期的session */ public class SessionScanerListener implements HttpSessionListener, ServletContextListener { // 创建一个线程安全的集合,用来存储session List<HttpSession> sessionList = Collections.synchronizedList(new LinkedList<HttpSession>()); private Object lock = new Object(); // 锁对象 public SessionScanerListener() { // TODO Auto-generated constructor stub } @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { System.out.println("session 创建中..."); HttpSession httpSession = httpSessionEvent.getSession(); synchronized (lock) { sessionList.add(httpSession); } System.out.println("session 创建成功!"); } @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { System.out.println("session 销毁成功"); } // web应用启动时触发 @Override public void contextInitialized(ServletContextEvent arg0) { System.out.println("web 应用初始化..."); Timer timer = new Timer(); timer.schedule(new MyTask(sessionList,lock), 0, 1000*30); } // web应用关闭时触发 @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("web 应用关闭"); } }
MyTask.java
package com.mimvp.listen; import java.util.List; import java.util.ListIterator; import java.util.TimerTask; import javax.servlet.http.HttpSession; public class MyTask extends TimerTask { private List<HttpSession> sessionList; private Object lock; // 存储传递过来的锁 // 构造方法 MyTask(List<HttpSession> list, Object lock){ this.sessionList = list; this.lock = lock; } @Override public void run() { // 考虑到多线程的情况,这里必须要同步 synchronized (lock) { System.out.println("定时器开始执行..."); ListIterator<HttpSession> listIterator = sessionList.listIterator(); while(listIterator.hasNext()) { HttpSession httpSession = listIterator.next(); // httpSession.getLastAccessedTime() = session的最后访问时间 long waitTime = System.currentTimeMillis() - httpSession.getLastAccessedTime(); if(waitTime > 1000 * 30) { httpSession.invalidate(); // 手动销毁session listIterator.remove(); // 从集合中移除已经被销毁的session } } } } }
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2017-05-03 23:17:13
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!