java监听器Listener

686 阅读4分钟

Java监听器(Listener)

Servlert的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,随着web应用的启动而启动,只初始化一次,随web应用的停止而销毁。

1.主要作用:

application、session、request三个对象创建、销毁时候或者往其中添加修改删除属性时自动执行代码的功能组件

做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者一个固定的对象等等


public interface ServletContextListener extends EventListener {
    //应用监听器的初始化方法
    public void contextInitialized(ServletContextEvent sce);
    //应用监听器的销毁方法
    public void contextDestroyed(ServletContextEvent sce);
}
1.ServletContextListener:对Servlet上下文的创建和销毁进行监听。
class test implements ServletContextListener{
 /**
  * 当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,
  * 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
  */
 contextInitialized(ServletContextEvent sce) ;
 /**
  * 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。
  */
 contextDestroyed(ServletContextEvent sce);
}
2.ServletContextAttributeListener:监听Servlet上下文属性的添加、删除和替换。
class test implements ServletContextAttributeListener{
    //在程序运行过程中,req.getServletContext().setAttribute(“”,something); 时发挥作用
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
       System.out.println("添加了一个ServletContext属性");

    }
    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
      System.out.println("移除了一个ServletContext属性");
    }
    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
       System.out.println("修改了一个ServletContext属性的作用范围");
    }
}
3.HttpSessionListener:对Session的创建和销毁进行监听。
class test implements HttpSessionListener{
//session创建
public void sessionCreated(HttpSessionEvent se);
//session销毁
public void sessionDestroyed(HttpSessionEvent se);
//HttpSessionEvent事件:
//取得当前操作的session
public HttpSession getSession();
}

补充:session的销毁有两种情况:1.session超时

​ 2.通过调用session对象的invalidate()方法使session失效。

4.HttpSessionAttributeListener:对Session对象中属性的添加、删除和替换进行监听。
class test implements HttpSessionAttributeListener{
public void attributeAdded(HttpSessionBindingEvent se);//增加属性
public void attributeRemoved(HttpSessionBindingEvent se);//删除属性
public void attributeReplaced(HttpSessionBindingEvent se);//替换属性

//HttpSessionBindingEvent事件:
public String getName();//取得属性的名称
public Object getValue();//取得属性的值
public HttpSession getSession();//取得当前的session
}
5.ServletRequestListener:对请求对象的初始化和销毁进行监听。
class test implements ServletRequestListener{
public void requestInitialized(ServletRequestEvent sre);//request初始化,对实现客户端的请求进行监听
public void requestDestroyed(ServletRequestEvent sre);//对销毁客户端进行监听,即当执行request.removeAttribute("XXX")时调用
//ServletRequestEvent事件:
public ServletRequest getServletRequest();//取得一个ServletRequest对象
public ServletContext getServletContext();//取得一个ServletContext(application)对象
}
6.ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。
class test implements ServletRequestAttributeListener{
public void attributeAdded(ServletRequestAttributeEvent srae);//增加属性
public void attributeRemoved(ServletRequestAttributeEvent srae);//属性删除
public void attributeReplaced(ServletRequestAttributeEvent srae);//属性替换(第二次设置同一属性)
//ServletRequestAttributeEvent事件:能取得设置属性的名称与内容
public String getName();//得到属性名称
public Object getValue();//取得属性的值
}

2.常见使用场景:

初始化基础数据
/**
 * @author yhwang
 * @date 2021年06月24日 17:55
 */
@Component
public class ListenerTest implements ServletContextListener, ApplicationContextAware {
    //其实这个就是spring的IOC容器-spring上下文应用程序  实现了ApplicationContextAware接口可以获取当前的上下文对象
    private static ApplicationContext applicationContext;
    @SuppressWarnings("static-access")
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    //应用监听器的初始化方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //整个javaWeb应用页面作用域servlet上下文,生命周期整个应用,可以往域对象里面添加,删除,修改数据;
        ServletContext servletContext = servletContextEvent.getServletContext();
        StudentService studentService = (StudentService) applicationContext.getBean("studentService");// 查询学生信息
        System.out.println(studentService.list());
        servletContext.setAttribute("学生列表",studentService.list());
    }
    //应用监听器的销毁方法
    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}
统计当前在线人数
@Component
public class SessionListenerTest implements HttpSessionListener {

    public static int ONLINE_USERS_TOTAL = 0;

    /**
     * session创建时
     * @param httpSessionEvent
     */
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        ServletContext application = httpSessionEvent.getSession().getServletContext();
        Integer online_users_total = (Integer) application.getAttribute("ONLINE_USERS_TOTAL");
        // 如果用户登录,ONLINE_USERS_TOTAL
        if(ONLINE_USERS_TOTAL==0){
            application.setAttribute("ONLINE_USERS_TOTAL",1);
        }else{
            application.setAttribute("ONLINE_USERS_TOTAL",online_users_total);
        }
        ONLINE_USERS_TOTAL++;
        System.out.println(ONLINE_USERS_TOTAL+"login");
    }

    /**
     * session销毁时
     * @param httpSessionEvent
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        // 如果用户退出,ONLINE_USERS_TOTAL
        ServletContext application = httpSessionEvent.getSession().getServletContext();
        ONLINE_USERS_TOTAL--;
        application.setAttribute("ONLINE_USERS_TOTAL",ONLINE_USERS_TOTAL);
        System.out.println(ONLINE_USERS_TOTAL+"logout");
    }
}
定期清理session
/**
 * @author yhwang
 * @date 2021年06月24日 18:57
 * @description 当网站用户量增加时,session占用的内存会越来越大,这时session的管理,将会是一项很大的
 * 系统开销,为了高效的管理session,我们可以写一个监听器,定期清理掉过期的session
 */
@Component
public class SessionScanerListener implements HttpSessionListener, ServletContextListener {
    // 创建一个线程安全的集合,用来存储session
    @SuppressWarnings("unchecked")
    List<HttpSession> sessionList = Collections.synchronizedList(new LinkedList<HttpSession>());
    private Object lock = new Object();

    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("session 创建成功...");
        HttpSession httpSession = httpSessionEvent.getSession();
        synchronized (lock){
            sessionList.add(httpSession);
        }
    }

    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("session 销毁成功...");
    }
    // web应用关闭时触发contextDestroyed事件
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("web应用关闭...");
    }

    // web应用启动时触发contextInitialized事件
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("web应用初始化...");
        // 创建定时器
        Timer timer = new Timer();
        // 每隔30秒就定时执行任务
        timer.schedule(new MyTask(sessionList,lock), 0, 1000*30);
    }
}
public class MyTask  extends TimerTask {
    private List<HttpSession> list;
    // 存储传递过来的锁
    private Object lock;
    // 构造方法
    public MyTask(List<HttpSession> list, Object lock){
        this.list = list;
        this.lock = lock;
    }
    @Override
    public void run() {
        // 考虑到多线程的情况,这里必须要同步
        synchronized (lock){
            System.out.println("定时器开始执行...");
            ListIterator<HttpSession> listIterator = list.listIterator();
            while(listIterator.hasNext()){
                HttpSession httpSession = listIterator.next();
                // httpSession.getLastAccessedTime() = session的最后访问时间
                if(System.currentTimeMillis() - httpSession.getLastAccessedTime() > 1000*30){
                    // 手动销毁session
                    httpSession.invalidate();
                    // 从集合中移除已经被销毁的session
                    listIterator.remove();
                }
            }
        }
    }
}