The previous Blog introduced the Servlet filter in detail and learned that the filter is similar to an AOP concept. This Blog will learn about the Servlet listener and understand what the third largest component of Java Web is useful and how it works.
Basic concepts of listener
In JSP technology, we have learned four scopes: pageContext, request, session and application, which are used to realize data sharing. The three scopes of request, session and application correspond to us respectively
- HttpServletRequest interface: request scope object
- HttpSession interface: session scope object
- ServletContext interface: global scope object
Although there is a scope for data sharing, we can't see the specific flow process of data, such as when the scope objects are created and destroyed, accessed, changed and deleted. Therefore, we can't operate the data and objects at the specified time. At this time, we need the Servlet listener to play a role:
- Events: method call, attribute change, state change, etc., which correspond to the creation and destruction events of objects, attribute change events, and additional events for monitoring the state change of objects in HttpSession.
- Event source: the monitored object. Here are HttpServletRequest, HttpSession, and ServletContext.
- Listener: used to listen to the event source object. Changes in the state of the event source object will trigger the listener. Here is a Servlet listener we created
- Register listener: bind the listener to the event source
So one sentence description is: after registering the listener for the event source, when an event causes a change in the event source, the listener listens to the change and performs logical processing
Listener function
Servlet listener is a special class defined in the servlet specification. It is used to listen to the creation and destruction events of three scope objects: servletContext(application), httpsession(session) and servletRequest(request), as well as the event of attribute modification in these scope objects. In other words, it is to listen to the life cycle of the three scope objects.
Create listener
You can easily create a listener with IDEA. Follow the steps below:
You can see that IDEA automatically generates the listener code template for us:
package com.example.myfirstweb.controller; /** * * @Name ${NAME} * * @Description * * @author tianmaolin * * @Data 2021/7/27 */ import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; @WebListener public class ServletListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener { public ServletListener() { } @Override public void contextInitialized(ServletContextEvent sce) { /* This method is called when the servlet context is initialized(when the Web application is deployed). */ } @Override public void contextDestroyed(ServletContextEvent sce) { /* This method is called when the servlet Context is undeployed or Application Server shuts down. */ } @Override public void sessionCreated(HttpSessionEvent se) { /* Session is created. */ } @Override public void sessionDestroyed(HttpSessionEvent se) { /* Session is destroyed. */ } @Override public void attributeAdded(HttpSessionBindingEvent sbe) { /* This method is called when an attribute is added to a session. */ } @Override public void attributeRemoved(HttpSessionBindingEvent sbe) { /* This method is called when an attribute is removed from a session. */ } @Override public void attributeReplaced(HttpSessionBindingEvent sbe) { /* This method is called when an attribute is replaced in a session. */ } }
You can see that listeners are defined through annotations. Let's look at the source code of annotations:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package javax.servlet.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WebListener { String value() default ""; }
Common methods of listener
Eight listener interfaces are defined in the Servlet specification, which can be used to listen to the life cycle and attribute change events of ServletContext, HttpSession and ServletRequest objects. To develop a Servlet listener, you need to implement the corresponding listener interface and rewrite the methods in the interface:
Listener for listener object creation and destruction
The Servlet specification defines listeners that listen to the creation and destruction events of ServletContext, HttpSession and HttpServletRequest objects
Listener listening for property changes
The Servlet specification defines listeners that listen for attribute change events in three objects: ServletContext, HttpSession and HttpServletRequest. The three listener interfaces are ServletContextAttributeListener, HttpSessionAttributeListener and ServletRequestAttributeListener respectively. Three methods are defined in these three interfaces to handle the events of adding, deleting and replacing attributes in the monitored object. The corresponding method names of the same event in the three interfaces are exactly the same, but the parameter types are different
Listener listening for object state changes in Session
Objects in a Session can have a variety of states: bind to the Session, unbind from the Session, persist to the storage device with the Session object (passivation), and recover from the storage device with the Session object (activation). Two special listener interfaces are defined in the Servlet specification to help objects understand their status in the Session: HttpSessionBindingListener interface and HttpSessionActivationListener interface. Classes implementing these two interfaces do not need to be registered
Listener to monitor the number of people online
Monitor the number of online people on the website, that is, count the number of sessions created in the server, and the number of online people created once + 1; session destroys the number of people online once - 1.
JSP page
If the login is successful, jump to index The JSP page is linked with the filter in the previous article. All page requests come to login first JSP, jump only after login. Here we simulate the jump after successful login:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*" errorPage="jsp/error.jsp" %> <%@ include file="jsp/top.jsp" %> <!DOCTYPE html> <html> <head> <title>JSP - Hello World</title> <%! int number = 0;// Declare global variables int count() { number++;//number self increment return number; }%> </head> <h1><%= "Hello World!" %> </h1> <br/> <body> <% String print = "I am the content of the script statement"; List<String> strList = new ArrayList<>(); strList.add("Script statement 1"); strList.add("Script statement 2"); strList.add("Script statement 3"); // strList.add("script statement 4")// This is a Java annotation used to annotate java code, which is not visible when viewing the source code %> <a href="hello-servlet">My first JavaWeb project</a> <!-- This is a html Notes, visible<%=new Date().getTime() %> --> <br/> <%--This is a JSP Comments, not visible when viewing the source code--%> Example declaration statement: This is the second statement <%=count()%> Visit this page for the first time <br/> Example of expression statement: <%="I am an expression statement"%> <br/> Example script statement: <%=print%>, Print list <%=strList%> </body> </html>
Servlet page
We prepare two pages. One page is used to jump from Servlet to index JSP, automatically exit after 60 seconds:
package com.example.MyFirstJavaWeb; import java.io.*; import javax.servlet.http.*; import javax.servlet.annotation.*; @WebServlet(name = "helloServlet", value = "/hello-servlet") public class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { //Assuming successful login HttpSession session = request.getSession(); session.setMaxInactiveInterval(60); //Auto launch in 60 seconds response.sendRedirect("index.jsp"); } public void destroy() { } }
There is also a page for manually exiting a session:
package com.example.MyFirstJavaWeb; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet(name = "StopSession", value = "/stop-servlet") public class StopSession extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { //Assuming successful exit HttpSession session = request.getSession(); session.invalidate(); } public void destroy() { } }
Servlet listener
The next step is the code of our listener. During application initialization, we add a quantity statistics, and then accumulate it when the session is created and subtract it when it is destroyed:
package com.example.MyFirstJavaWeb.listener; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.util.Date; @WebListener public class CountListener implements HttpSessionListener,ServletContextListener { public CountListener() { } //Listen to the application destruction event -- that is, the server is shut down @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("application Destroy~~~~~~~~"); } //Listen to the application creation event -- that is, the server is turned on @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("application establish~~~~~~~~"); int sessionCount = 0;//When the server is turned on, variables are defined to count the number of online people and save them ServletContext application = sce.getServletContext(); application.setAttribute("sessionCount", sessionCount); } //Listen to the session creation event -- that is, if someone logs in successfully and enters the main page of the project, the number of online people + 1 @Override public void sessionCreated(HttpSessionEvent hse) { System.out.println("Login successful"+hse.getSession().getId()+"Created on:"+new Date()); ServletContext application = hse.getSession().getServletContext(); int sessionCount = (int)application.getAttribute("sessionCount"); application.setAttribute("sessionCount", ++sessionCount); System.out.println("The current number of online users is:"+application.getAttribute("sessionCount")); } //Listen for session destruction events - there are many ways to destroy: forced destruction, automatic expiration, etc. it doesn't matter. You can listen as long as the session is destroyed @Override public void sessionDestroyed(HttpSessionEvent hse) { System.out.println("Exit successful"+hse.getSession().getId()+"Exit time:"+new Date()); ServletContext application = hse.getSession().getServletContext(); int sessionCount = (int)application.getAttribute("sessionCount"); application.setAttribute("sessionCount", --sessionCount); System.out.println("The current number of online users is:"+application.getAttribute("sessionCount")); } }
Realization effect
In this way, every time we visit a page through different browsers, a new user will be added. The whole change process is as follows:
Pay attention to tick this off, otherwise the idea will generate an additional session for you at startup, and there will be two sessions at startup.
To sum up
In fact, the biggest function of Servlet listener is to be regarded as a state machine. In fact, in any process, it is abstracted through the life cycle management of events to event sources. Objects flow in the process driven by events. The same is true in system design, so in fact, the listener can make us understand more about the design idea of event driven life cycle. Just as the filter gives us more understanding about the control of AOP on all services, the more important thing is the idea, and the components are just the landing of ideas. With ideas, we can apply them in more places.