Article From:https://www.cnblogs.com/huangdabing/p/9219434.html

  Listeners are widely used in JavaWeb development. Let’s talk about the common applications of Listener in development:

  Statistics on current online numbers

  Custom Session scanner

1. Statistics on current online numbers

  In JavaWeb application development, sometimes we need to count the current number of users online, so we can use listener technology to achieve this function.

package com.web.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
* @ClassName: OnLineCountListener
* @Description: Count the number of current online users*@author: hdb
* @date: 2017-12-10 10:01:26
*
*/ 
public class OnLineCountListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        ServletContext context = se.getSession().getServletContext();
        Integer onLineCount = (Integer) context.getAttribute("onLineCount");
        if(onLineCount==null){
            context.setAttribute("onLineCount", 1);
        }else{
            onLineCount++;
            context.setAttribute("onLineCount", onLineCount);
        }
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext context = se.getSession().getServletContext();
        Integer onLineCount = (Integer) context.getAttribute("onLineCount");
        if(onLineCount==null){
            context.setAttribute("onLineCount", 1);
        }else{
            onLineCount--;
            context.setAttribute("onLineCount", onLineCount);
        }
    }
}

Two. Custom Session scanner

  When a Web application creates a lot of Session, in order to avoid Session taking too much memory, we can choose to manually destroy the session in the memory, then we can also use the listener technology to implement it.

package com.web.listener;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
* @ClassName: SessionScanerListener
* @Description: Custom session scanner*@author: hdb
* @date: 2017-12-10 10:16:42
* 
*/ 
public class SessionScanerListener implements HttpSessionListener,ServletContextListener {

    /**
    * @Field: list
    *        Define the HttpSession created by a collection storage server.* LinkedListNot a thread safe collection*/ 
    /**
     * private List<HttpSession> list = new LinkedList<HttpSession>();
     * This writing involves thread safety problem, and SessionScanerListener object has only one memory.* sessionCreated may be called by multiple individuals at the same time.* when there are multiple concurrency visits to the site,The server also creates session for those concurrent visitors.* then the sessionCreated method will be called at the same time by several threads at a certain time, and several threads call sessionCreated method concurrently.* SESThe internal processing of the sionCreated method is to add a created session to a collection, so when session is added, it will*It involves several Session while grabbing a location in the collection, so when adding session to the collection, ensure that the collection is thread safe.
     * How to make a collection a thread safe set?*You can use Collections.synchronizedList (List< T> list) to wrap a thread safe list set from a thread set that is not thread safe.*/
    //Use Collections.synchronizedList (List< T> list) method to wrap LinkedList into a thread safe set.
    private List<HttpSession> list = Collections.synchronizedList(new LinkedList<HttpSession>());
    //Define an object, let the object act as a lock, and use this lock to ensure that the new session added to the list set and the two operations that traverse the session in the list collection are synchronized.
    private Object lock = new Object();
            
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("sessionIt was created!);
        HttpSession session = se.getSession();
        
        synchronized (lock){
            /**
             *Lock the operation with the lock, when a thread-1 (thread 1) is calling the code, the lock is first obtained by lock, and then session is added to the collection.* in the process of adding session, it is assumed that there is anotherAn external thread-2 (thread 2) is accessed, and thread-2 may execute the timer task.* when thread-2 calls the run method to traverse the session in the list collection, it turns out that traversal LiThe code for session in the st collection is locked.* the lock is occupied by the thread-1 that is added to session in the collection, so thread-2 can only wait for the thread-1 operation to complete.Only after the operation can be done* when thread-1 is finished with session, lock is released. When thread-2 gets lock, it can execute the code that traverses the session in the list set.* this lock ensures that the two steps of adding session to the set and the session in the set of variables cannot be carried out at the same time, and must be carried out in the first order.*/
            list.add(session);
        }
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("sessionIt's destroyed!! ");
    }

    /* WebThe application triggers this event when the application is started* @see javax.servlet.ServletContextListener#contextInitialized (javax.servlet.Servle)TContextEvent)*/
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("webApplication initialization ");
        //create-timer
        Timer timer = new Timer();
        //Perform tasks regularly every 30 seconds
        timer.schedule(new MyTask(list,lock), 0, 1000*30);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("webApplication closes ");
    }
}

/**
* @ClassName: MyTask
* @Description:The task of timers to be executed regularly*@author: hdb
* @date: 2017-12-11 12:02:36
*
*/ 
class MyTask extends TimerTask {
        
    //The list set for storing HttpSession
    private List<HttpSession> list;
    //Store the transfer lock
    private Object lock;
    public MyTask(List<HttpSession> list,Object lock){
        this.list = list;
        this.lock = lock;
    }
    /* runThe method points out what the task is to do* @see java.util.TimerTask#run ()*/
    @Override
    public void run() {
            //Lock the operation with lock
        synchronized (lock) {
            System.out.println("The timer is executed!! ");
            ListIterator<HttpSession> it = list.listIterator();
            /**
             * Iterating the session in the list set, there may be other users accessing the session in the iteration of the list set.* once the user accesses, the server will create a session for the user, which will be called at that time.SessionCreated adds a new session to the list collection.* however, it is impossible for the timer to scan the list collection to scan the session set when it is executing the scan regularly. The list collection is also added.The new session comes in,* this causes the two operations that are added to the list collection and the traversal of session in the list set can not be synchronized with the session.* thatThe solution is to synchronize the two sections of "list.add (session) and while (it.hasNext ())} / / iterated list set}".* ensure that a thread is accessing the "Li"When st.add (session) "this code, another thread will not be able to access" while (it.hasNext ())} / / iterated list set} "this code.* in order to be able to do the two pieces of unrelated codeIn order to synchronize, you can only define a Object lock, and then add the same lock to these two steps.* use this lock to ensure the new session added to the list collection and traverse the session in the list collection.These two operations are synchronized* when a new session operation is added to the list set, it is necessary to iterate the list set until the completion is completed.* when in the execution of theWhen the list set performs iterative operations, it is necessary to wait until the end of the iteration to get the new session added to the list collection.*/
            while(it.hasNext()){
                HttpSession session = (HttpSession) it.next();
                /**
                 * If the current time -session last access time > 1000*15 (15 seconds)* session.getLastAccessedTime () gets the last access to session.time*/
                if(System.currentTimeMillis()-session.getLastAccessedTime()>1000*30){
                    //Manually destroy session
                    session.invalidate();
                    //Remove the session that has been destroyed in the collection
                    it.remove();
                }
            }
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *