监听器

1 事件三要素
  a)事件源:操作事件的对象,例如:窗体Frame
  b)事件监听器:事件监听器监听事件源,例如WindowListner,它是一个接口
  c)事件,例如:单击事件,通过事件,可以取得事件源

2 适配器模式
  a)当一个接口有较多的方法时,而实现类只需对其中少数几个实现,此时可以使用适配器模式
  b)适配器模式常用于GUI编程,而web监听器中并不存在Adapter(适配器)

*3 八种web监听器详解
  a)Web中有三个事件源,分别是ServletContext->HttpSession->ServletRequest
    ***注意:Listener都是单例模式,当web应用启动时创建Listener实例,并在web应用停止时销毁Listener实例。
  b)ServletContext对象
    >>创建和销毁:ServletContextListener.
      Web容器部署时容器自动调用contextInitialized()方法,
      Web容器重新部署时容器自动调用contextDestroyed()方法。
    >>属性变化:ServletContextAttributeListner
      application.setAttirbute("name","jack") ----> void attributeAdded(ServletContextAttributeEvent event)
      setAttribute("name","杰克") ----> void attributeReplaced(ServletContextAttributeEvent event)
      removeAttribute("name") ----> void attributeRemoved(ServletContextAttributeEvent event)

案例:
   1)利用监听器初始化数据库
    

code:
      public class MyServletContextListener implements ServletContextListener {
        private ContextDao dao = new ContextDao();
        @Override
        public void contextInitialized(ServletContextEvent event) {
          try {
            dao.createTable();
            System.out.println("创建表成功!");
            dao.insertTable("jack");
            System.out.println("插入数据成功!");
          } catch (SQLException e) {
            e.printStackTrace();
          }
        }
        @Override
        public void contextDestroyed(ServletContextEvent event) {
          try {
            dao.dropTable();
            System.out.println("删除表成功!");
          } catch (SQLException e) {
            e.printStackTrace();
          }  
        }
       }

  web.xml
    <listener>
      <listener-class>listener.context.MyServletContextListener</listener-class>
    </listener>

 

  


2) 指定时间往数据库插入一次数据,5秒的延迟
  

public class MyServletContextListener1 implements ServletContextListener {
    private TimerDao dao = new TimerDao();
    private Timer timer;
    private TimerTask task;
    public MyServletContextListener1() {
      this.timer = new Timer();
      /*初始化TimerTask对象*/
      task = new TimerTask() {
      @Override
      public void run() {
        try {
          dao.insertTable(UUID.randomUUID().toString(), new Date());
        } catch (SQLException e) {
          e.printStackTrace();
        }
      }
    };
  }
  public void contextInitialized(ServletContextEvent event) {
    try {
      dao.createTable();
      //每隔5秒像数据库插入一条数据
      timer.schedule(task, 0, 1000*5);
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  public void contextDestroyed(ServletContextEvent event) {
    try {
      dao.destoryTable();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
 }

 

 

 

3)ServletContextAttributeListener测试
code:

//listener
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
System.out.println("attributeAdded==>" + event.getName() + " : " + event.getValue());
}
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
//注意:此时的getValue得到的是替换前的value值。
System.out.println("attributeReplaced==>" + event.getName() + " : " + event.getValue());
}
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
System.out.println("attriattributeRemoved==>" + event.getName() + " : " + event.getValue());
}
}
//java
application.setAttribute("name", "jack");
application.setAttribute("name", "杰克");
application.removeAttribute("name");
//输出结果:
attributeAdded==>name : jack
attributeReplaced==>name : jack
attriattributeRemoved==>name : 杰克 
c)ServletRequest对象
>>创建和销毁:ServletRequestListener.
每次请求容器自动调用requestInitialized()方法,
响应完毕容器自动调用requestDestroyed()方法
>>属性变化:ServletRequestAttributeListner(与ServletContextAttributeListener类似,例子省略)
request.setAttirbute("name","jack")
setAttribute("name","杰克")
removeAttribute("name")

 

案例:
1)回写显示访问此网站的次数,访问者ip,以及访问者本地时间【js】。

code:
public class MyServletRequestListener implements ServletRequestListener {
private Integer queryNum = 0;
@Override
public void requestDestroyed(ServletRequestEvent event) {
System.out.println("requestDestroyed()");
}
@Override
public void requestInitialized(ServletRequestEvent event) {
HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
String ip = request.getRemoteAddr();
synchronized (this) {
queryNum++;
}
request.setAttribute("ip", ip);
request.setAttribute("num", queryNum);
System.out.println("requestInitialized()");
}
}
js:
<script type="text/javascript">
function nowTime() {
window.setInterval("updateTime()", 1000);
}
function updateTime() {
var nowDate = new Date().toLocaleString();
//定位区域并输出
var spanElement = document.getElementById("spanId");
spanElement.innerHTML = nowDate;
}
</script>
</head>
<body onload="nowTime()">
您的ip:${requestScope.ip} <br/>
网站访问次数:${requestScope.num} <br/>
当前时间:<span id="spanId"></span> <br/>
</body>

 


d)HttpSession对象
>>创建和销毁:HttpSessionListener.
当Web容器创建HttpSession对象时容器自动调用sessionCreated()方法
当Web容器销毁HttpSession对象时容器自动调用sessionDestroyed()方法
>>属性变化:HttpSessionAttributeListner (与ServletContextAttributeListener类似,例子省略)
session.setAttirbute("name","jack")
setAttribute("name","杰克")
removeAttribute("name")

案例:
1)HttpSessionListener调用函数测试

web.xml
<listener>
<listener-class>listener.session.MyHttpSessionListener</listener-class>
</listener>
<!-- 设置session的过期时间为1分钟,默认为30分钟 【注意:实际上时间并不为1分钟】-->
<session-config>
<session-timeout>1</session-timeout>
</session-config>

code:
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
//若为新创建的session
if (session.isNew()) {
System.out.println("sessionCreated, ID:" + session.getId());
}
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
if (!session.isNew()) {
System.out.println("sessionDestroyed, ID:" + session.getId());
}
}
}

 

2)利用Session扫描器:精确控制session的声明周期
code:

public class SessionScanner implements HttpSessionListener, ServletContextListener {

private List<HttpSession> sessionList = Collections.synchronizedList(new ArrayList<HttpSession>());
Timer timer = new Timer();
@Override
public void contextInitialized(ServletContextEvent event) {
timer.schedule(new MyTimerTask(sessionList), 0, 1*1000);
}
@Override
public void contextDestroyed(ServletContextEvent event) {
//取消当前定时器
timer.cancel();
}

@Override
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
synchronized (sessionList) {
sessionList.add(session);
}
System.out.println("Session产生:" + session.hashCode() + " : " + new Date().toLocaleString() );
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
System.out.println("Session销毁:" + session.hashCode() + " : " + new Date().toLocaleString());
}
}

class MyTimerTask extends TimerTask {
public MyTimerTask(List<HttpSession> sessionList) {
this.list = sessionList;
}
@Override
public void run() {
synchronized (list) {
    ListIterator<HttpSession> listIt = list.listIterator();
    while(listIt.hasNext()) {
    HttpSession session = listIt.next();
    //测试HttpSession的存在时间
    int middle = (int) ( System.currentTimeMillis() -             session.getLastAccessedTime() ) / 1000;
if (middle > 60 ) {
//从list中移除当前HttpSession元素
listIt.remove();
//使得此session失效
session.invalidate();
}
}
}
}
}    

 


e)HttpSessionBindListener监听器,专用于监听JavaBean对象在HttpSession中的状态情况:
检测JavaBean在Session中的状态,感知自己何时绑定在HttpSession中,何时从HttpSession中移除。
code:

//listener
public class User implements HttpSessionBindingListener {
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("valueBound==>" + event.getName() + " : " + event.getValue());
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("valueUnbound==>" + event.getName() + " : " + event.getValue());
}
}
//java
session.setAttribute("user", new User());
try {
Thread.sleep(10000);
} catch (Exception e) {

}
session.removeAttribute("user");

  

运行结果:

valueBound==>user : listener.domain.User@5f5220ee
valueUnbound==>user : listener.domain.User@5f5220ee

 


f)HttpSessionActivationListener监听器,专用于监听JavaBean对象的钝化与激活:
钝化与激活概念:
1)当HttpSession不用时,但用在HttpSession的有效期中,这时将内存中的HttpSessio移到外存,叫钝化。
2)反之,将HttpSession由外存移到内存,叫激活。
JavaBean对象,感知自己何时被钝化,合适被激活,由web容器决定。
配置钝化激活时间:
针对所有项目:在tomcat的conf/context.xml进行配置.
针对单个项目:只需在此项目的META-INF/加入一个context.xml文件即可。
配置内容如下:

<?xml version="1.0" encoding="utf-8"?>
<Context>
<Manager 
className="org.apache.catalina.session.PersistentManager"
maxIdleSwap="1"> //设置session钝化时间为1分钟
<Store 
className="org.apache.catalina.session.FileStore"
directory="target" /> //设置钝化文件目标存放目录
</Manager>
</Context>

 


默认钝化文件.session的目标文件夹为: tomcat的work目录下。

code:

public class Stu implements HttpSessionActivationListener {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void sessionDidActivate(HttpSessionEvent event) {
System.out.println("sessionDidActivate");
}
@Override
public void sessionWillPassivate(HttpSessionEvent event) {
System.out.println("sessionWillPassivate");
}
}

  


注意: 但凡是监听三个域对象,就需要在web.xml文件中配置,除外,无需要web.xml文件配置。
所以:
HttpSessionBindListener和HttpSessionActivationListener监听器无需在web.xml中进行配置。

4 监听器的工作过程和生命周期
开发过程:
a)写一个普通类实现对应的接口,即事件监听器
b)在web.xml文件中注册事件监听器
<!-- 事件源注册事件监听器,由容器完成 -->
<listener>
<listener-class>cn.itcast.web.listener.MyServletContextListener</listener-class>
</listener>

生命周期:
*空参构造(1次)->初始化(1次)->销毁化(1次),是一个单例的模式

在部署web应用是产生,即用户第一次访问之前已经产生,在重新部署web应用时,后销毁原监听器,再产生新的监听器

 

*5 案例
a)java.util.Timer定时器是以后台线程方式控制运行,它是线程安全,无需手工加锁
b)timer.schedule(new MyTimerTask(),0,5000);固定频度执行
c)Calendar c = Calendar.getInstance();
c.set(2011,10,6,10,30,40);
timer.schedule(new MyTimerTask(),c.getTime());指定时间执行
d)***Serlvet,Filter和Listener一样具有线程安全问题
e)当HttpSession过期时,Web容器负付执行对应的销毁方法,但是时间不精确
f)**Listener在Jsp或Servlet之前被执行
g)在线人数使用:context,第N个访问者使用:session


*补充:Timer类 ———— 定时器(线程安全的)
补充:timer.cancel() 方法,可以终止Timer定时器

public class TimerDemo {
public static void main(String[] args) {
Timer timer = new Timer();
//延迟5秒进行,并每隔1秒执行一次任务
//timer.schedule(new MyTimerTask(), 5000, 1000);

//在2015年1月12日15时34分50秒执行一次任务
Calendar calendar = Calendar.getInstance();
calendar.set(2015, 0, 12, 15, 34, 50);

timer.schedule(new MyTimerTask(), calendar.getTime());
}
}
class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println(new Date().toLocaleString());
}
}

 

 

posted on 2015-01-14 20:43  SkyGood  阅读(309)  评论(0编辑  收藏  举报