设计模式(Javaee)之---监听者模式
Posted 夏小弥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式(Javaee)之---监听者模式相关的知识,希望对你有一定的参考价值。
监听者模式
一、
监听者模式也叫观察者模式
监听器Listener
监听器-就是一个实现待定接口的普通Java程序,此程序专门用于监听别一个类的方法调用。
都是使用观察者设计模式。
什么是观察者模式:
定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。
示例:
GUI编程中的addXxxxListener都是观察者模式。
观察者模式的三个重要类:
观察者设计模式示例:
1、开发步骤:
* 第一步:实现一个需要被监听的类Person.
* 第二步:实现一个监听接口PersonListener。
* 第三步:在Person类中,提供一个方法用于注册PersonListener类,即registerListener
* 第四步:必须要在Person类中维护PersonListener类的实例。
* 第五步:在调用person.eat方法是,判断PersonListener是否为null,如果不为null则调用它的eating方法。
* 第六步:在Main类中,实例化Person,并注册一个监听。
被监听者Person
package cn.hncu.designPattern;
public class Person
private String name;
private IPersonRunListener listener1;
private IPersonRunListener listener2;
public Person(String name)
this.name = name;
public void run()
if(listener1!=null)
listener1.fighting();
System.out.println(this.name + " is running....");
if(listener2!=null)
listener2.fighting();
public void addBefore(IPersonRunListener listener)
this.listener1 = listener;
public void addAfter(IPersonRunListener listener)
this.listener2 = listener;
interface IPersonRunListener
public void fighting();
监听者
package cn.hncu.designPattern;
public class Demo
public static void main(String[] args)
Person p = new Person("Jack");
IPersonRunListener a = new A();
p.addAfter(a);
p.addBefore( new IPersonRunListener()
@Override
public void fighting()
System.out.println("注意做点准备活动....");
);
p.run();
class A implements IPersonRunListener
@Override
public void fighting()
System.out.println("加油...做死的跑...");
第一步:前页改Person为Cat的基础上继续添加一个CatEvent类(注意我说是类不是接口),代表事件对像。
第二步:修改ICatListener接口的climbing方法,让它接收一个 CatEvent参数。
第三步:在Cat类climbing方法中,如果判断ICatListener属性不为空,则在调用climbing方法,实例化 CatEvent并传给climbing方法。
第四步:在main方法中,通过 CatEvent的getSource方法测试是否是同一个对像。
package cn.hncu.designPattern.two;
public class Cat
private ICatListener listener = null;
private String name;
public Cat(String name)
this.name = name;
public String getName()
return name;
public void climb()
System.out.println(name+"正在爬.....");
if (listener != null)
listener.help(new CatEvent(this));
public void addCatListener(ICatListener listener)
this.listener = listener;
@Override
public String toString()
return name;
interface ICatListener
public void help(CatEvent e);
class CatEvent
private Cat cat = null;
public CatEvent(Cat cat)
this.cat = cat;
public Object getSource()
return cat;
public String getActionCommand()
return cat.getName();
class DefaultCatListener implements ICatListener
@Override
public void help(CatEvent e)
System.out.println("默认动作....");
package cn.hncu.designPattern.two;
public class Demo2
public static void main(String[] args)
Cat cat = new Cat("白猫");
Cat cat2 = new Cat("黑猫");
ICatListener ic = new ICatListener()
@Override
public void help(CatEvent e)
System.out.println(e.getSource() + "真调皮,你又爬了....");
if(e.getActionCommand().equals("白猫"))
System.out.println("喂鱼...");
;
cat.addCatListener(ic);
cat2.addCatListener(ic);
cat.climb();
Servlet技术的监听器(查看API)
监听示例1-监听ServletContext的创建和销毁:
开发步骤:
第一步:实现ServletContextListener接口。
第二步:实现两个方法。
contextInitialized
contextDestroyed
第三步:在web.xml中添加<listener/>节点。
这一点与swing中的添加监听有所区别。
第四步:测试
1、发布项目启动。
2、通过Tomcat管理控制台停止此项目。
监听示例2:-监听ServletContext上的属性变化:
这个比较简单就不多说了,如下图:
下面我们结合上面的监听示例1和2做一个应用实例
ContextListener应用场景:
记录一个网站的刷新量。
当服务器关闭时,必须要保存到文件中或是数据库中去。
当服务器启动时,先从文件中读取并放到ServletContext。
在Filter中记录访问量,每次访问都加1。
好处:信息不是太重要,没有必要每次用户访问都访问数据库或是操作文件。
在为不影响用户的速度感受,应该开始一个新的线程同去操作数据。
这样即使在后台使用同步技术,用户也不会感觉到速度很慢。
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>servlet监听器HelloWorld</title>
</head>
<body>
<h2>servlet监听器HelloWorld</h2> <br>
<h2>示例---网站点击量的实现</h2> <br>
点击量:$count
<a href="jsps/a.jsp">演示MyServletContextAttributeListener</a>
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<filter>
<filter-name>count</filter-name>
<filter-class>cn.hncu.filter.CountFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>count</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>cn.hncu.listener.MyContextListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
过滤器:CountFilter
package cn.hncu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class CountFilter implements Filter
@Override
public void init(FilterConfig filterConfig) throws ServletException
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
ServletContext ctx = request.getServletContext();
new MyThread(ctx).start();
chain.doFilter(request, response);
@Override
public void destroy()
class MyThread extends Thread
private ServletContext ctx=null;
private static Object obj = new Object();
public MyThread(ServletContext ctx)
this.ctx = ctx;
@Override
public void run()
synchronized (obj)
Integer count = (Integer) ctx.getAttribute("count");
count++;
ctx.setAttribute("count", count);
监听器:MyContextListener
package cn.hncu.listener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyContextListener implements ServletContextListener
@Override
public void contextInitialized(ServletContextEvent sce)
System.out.println("ServletContext对象(项目)创建了....");
//从服务器硬盘把之前存储的点击量数据读取出来
ServletContext ctx = sce.getServletContext();
String path= ctx.getRealPath("/count.txt");
try
BufferedReader br = new BufferedReader(new FileReader(path));
String line = br.readLine();
Integer count = Integer.valueOf(line);
ctx.setAttribute("count", count);
catch (Exception e)
e.printStackTrace();
ctx.setAttribute("count", new Integer(0));
@Override
public void contextDestroyed(ServletContextEvent sce)
System.out.println("ServletContext对象(项目)消亡了....");
//把当前servletContext容器中存储的点击量数据 永久化到 服务器硬盘
ServletContext ctx = sce.getServletContext();
String path= ctx.getRealPath("/count.txt");
try
PrintWriter pw = new PrintWriter(path);
pw.println(""+ctx.getAttribute("count"));
pw.close();
catch (Exception e)
e.printStackTrace();
HttpSession的监听器:
HttpSessionListener,监听HttpSession的创建和销毁。
sessionCreated
sessionDestroyed
Session的默认有效时间为30分。可以通过配置的方式修改它的值。
可以调用session.invalidate方法销毁当前Session.
主要作用是记录当前所有在线人数,无论是用户还是游客。
Session的属性设置监听事件:
HttpSessionAttributeListener
主要作用是:记录当前在登录人数。注意,登录是指注册成为合法用户并成功登录的人。
顺便提一个知识点
ServletRequestListener 经常用来记录访问量
ServletRequestAttributeListener:
下面做一个实例:
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示HttpSessionListener---示例:在线人信息</title>
</head>
<body>
<h3>演示HttpSessionListener---示例:在线人信息</h3>
<a href="<c:url value='/ShowServlet'/>">查看在线人</a>
<hr/>
<form action="<c:url value='/LoginServlet'/>" method="post">
姓名:<input type="text" name="name" />
<input type="submit" value="登录">
</form>
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<listener>
<listener-class>cn.hncu.listener.MyHttpSessionListener</listener-class>
</listener>
<listener>
<listener-class>cn.hncu.listener.MySessionAttrListener</listener-class>
</listener>
<servlet>
<servlet-name>ShowServlet</servlet-name>
<servlet-class>cn.hncu.servlet.ShowServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>cn.hncu.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ShowServlet</servlet-name>
<url-pattern>/ShowServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
MyHttpSessionListener.java
package cn.hncu.listener;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener
@Override
public void sessionCreated(HttpSessionEvent se)
System.out.println( "有人进来了..."+ se.getSession().getId() );
List<HttpSession> guests = (List<HttpSession>) se.getSession().getServletContext().getAttribute("guests");//在线人集合
if(guests==null)//沙发
guests = new ArrayList<HttpSession>();
se.getSession().getServletContext().setAttribute("guests", guests);
guests.add(se.getSession());
@Override
public void sessionDestroyed(HttpSessionEvent se)
System.out.println( "有人退出了..."+ se.getSession().getId() );
List<HttpSession> guests = (List<HttpSession>) se.getSession().getServletContext().getAttribute("guests");
if(guests.contains(se.getSession()))
guests.remove(se.getSession());
MySessionAttrListener.java
package cn.hncu.listener;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class MySessionAttrListener implements HttpSessionAttributeListener
@Override
public void attributeAdded(HttpSessionBindingEvent se)
if(se.getName().equals("name"))
System.out.println("用户"+se.getName()+"登录..."+se.getSession());
List<HttpSession> logins = (List<HttpSession>) se.getSession().getServletContext().getAttribute("logins");
if(logins==null)
logins = new ArrayList<HttpSession>();
se.getSession().getServletContext().setAttribute("logins",logins);
logins.add(se.getSession());
@Override
public void attributeRemoved(HttpSessionBindingEvent se)
@Override
public void attributeReplaced(HttpSessionBindingEvent se)
Servlet
LoginServlet.java
package cn.hncu.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String name = request.getParameter("name");
if(name!=null && name.trim().length()>0)//假定该情况是登录成功
request.getSession().setAttribute("name", name);
request.getSession().setAttribute("ip", request.getRemoteAddr());
out.println("登录成功!");
out.flush();
out.close();
ShowServlet.java
package cn.hncu.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
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 ShowServlet extends HttpServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
doPost(request, response);
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
List<HttpSession> guests =(List<HttpSession>) getServletContext().getAttribute("guests");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (guests!=null)
for(HttpSession s: guests)
Date d = new Date(s.getCreationTime());
out.println("ID:"+s.getId()+"," + sdf.format(d)+"<br/>");
out.println("<hr/>");
out.println("<h3>以下是已登录用户信息</h3>");
List<HttpSession> logins =(List<HttpSession>) getServletContext().getAttribute("logins");
if (logins!=null)
for (HttpSession s : logins)
out.println("ID:" + s.getId() + ", Name:"
+ s.getAttribute("name") + ",IP:"
+ s.getAttribute("ip") + "<br/>");
这一个例子因为这里只是讲知识点就并没有做得那么完善,下一篇博文将会做完善一点
以上是关于设计模式(Javaee)之---监听者模式的主要内容,如果未能解决你的问题,请参考以下文章