什么是监听器
监听器就是一个实现特定接口的普通 java 程序, 这个程序专门用于监听另一个 java 对象的方法调用或属性改变, 当被监听对象发生上述事件后, 监听器某个方法将立即被执行
为什么我们要使用监听器?
监听器可以用来检测网站的在线人数, 统计网站的访问量等等!
监听器组件
监听器涉及三个组件: 事件源, 事件对象, 事件监听器
当事件源发生某个动作的时候, 它会调用事件监听器的方法, 并在调用事件监听器方法的时候把事件对象传递进去
我们在监听器中就可以通过事件对象获取得到事件源, 从而对事件源进行操作!
模拟监听器
既然上面已经说了监听器的概念了, 监听器涉及三个组件: 事件源, 事件对象, 事件监听器
我们就写一个对象, 被监听器监听
监听器
监听器定义为接口, 监听的方法需要事件对象传递进来, 从而在监听器上通过事件对象获取得到事件源, 对事件源进行修改!
- /**
- * 事件监听器
- *
- * 监听 Person 事件源的 eat 和 sleep 方法
- */
- interface PersonListener {
- void doEat(Event event);
- void doSleep(Event event);
- }
事件源
事件源是一个 Person 类, 它有 eat 和 sleep() 方法
事件源需要注册监听器 (即在事件源上关联监听器对象)
如果触发了 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();
- }
事件源: 拥有事件
监听器: 监听事件源所拥有的事件 (带事件对象参数的)
事件对象: 事件对象封装了事件源对象
事件源要与监听器有关系, 就得注册监听器提供方法得到监听器对象
触发事件源的事件, 实际会提交给监听器对象处理, 并且把事件对象传递过去给监听器
Servle 监听器
在 Servlet 规范中定义了多种类型的监听器, 它们用于监听的事件源分别 ServletContext, HttpSession 和 ServletRequest 这三个域对象
和其它事件监听器略有不同的是, servlet 监听器的注册不是直接注册在事件源上, 而是由 web 容器负责注册, 开发人员只需在 web.xml 文件中使用 < listener > 标签配置好监听器,
监听对象的创建和销毁
HttpSessionListenerServletContextListenerServletRequestListener 分别监控着 SessionContextRequest 对象的创建和销毁
HttpSessionListener(可以用来收集在线者信息)
ServletContextListener(可以获取 web.xml 里面的参数配置)
ServletRequestListener
测试
- 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) {
- }
- }
监听器监听到 ServletContext 的初始化了, Session 的创建和 ServletContext 的销毁 (服务器停掉, 不代表 Session 就被销毁了 Session 的创建是在内存中的, 所以没看到 Session 被销毁了)
监听对象属性变化
ServletContextAttributeListenerHttpSessionAttributeListenerServletRequestAttributeListener 分别监听着 ContextSessionRequest 对象属性的变化
这三个接口中都定义了三个方法来处理被监听对象中的属性的增加, 删除和替换的事件, 同一个事件在这三个接口中对应的方法名称完全相同, 只是接受的参数类型不同
- attributeAdded()
- attributeRemoved()
- attributeReplaced()
测试
这里我只演示 Context 对象, 其他对象都是以此类推的, 就不一一测试了
实现 ServletContextAttributeListener 接口
- 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 对象替换了属性");
- }
- }
测试的 Servlet
- 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");
- }
监听 Session 内的对象
除了上面的 6 种 Listener, 还有两种 Linstener 监听 Session 内的对象, 分别是 HttpSessionBindingListener 和 HttpSessionActivationListener, 实现这两个接口并不需要在 web.xml 文件中注册
实现 HttpSessionBindingListener 接口, JavaBean 对象可以感知自己被绑定到 Session 中和从 Session 中删除的事件和 HttpSessionAttributeListener 的作用是差不多的
实现 HttpSessionActivationListener 接口, JavaBean 对象可以感知自己被活化和钝化的事件 (当服务器关闭时, 会将 Session 的内容保存在硬盘上钝化, 当服务器开启时, 会将 Session 的内容在硬盘式重新加载活化)
想要测试出 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");
效果:
来源: https://www.cnblogs.com/Java3y/p/8436237.html