Listener监听器和Filter过滤器
一、Listener监听器
1. Listener监听器介绍
Listener监听器它是JavaWeb的三大组件之一,JavaWeb的三大组件分别是:Servlet程序、Listener监听器、Filter过滤器
Listener是一个接口,是JavaWeb的规范的一种、
监听器的作用是:监听某种变化(如:对象的创建和销毁,属性的添加和删除等),然后再触发对应的方法完成相应的任务
JavaWeb中常用的监听器有八个,目前最常用的是ServletContextListener
流程图
2.ServletContextListener监听器
作用:监听ServletContext创建或销毁(当web应用启动时,就会创建ServletContext),可以理解为生命周期的监听
应用场景:
加载初始化的配置文件:比如spring的配置文件
任务调度(配合定时器Timer/TimerTask)
相关方法
package com.leon.listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * ClassName:ContextListener * Package:com.leon.listener * Description: * * @Author: leon-->ZGJ * @Create: 2023/11/9 16:57 * @Version: 1.0 */ /** * 1. 当一个类实现了ServletContextListener接口,该类就是一个监听器了 * 2. 该类可以监听的事件由该类所实现的接口所决定的。 * 比如:实现ServletContextListener,则该类就可以监听ServletContext对象的创建和销毁,其 他的以此类推 * 3.ContextListener就是一个监听者 * 4.当web应用启动时,就会产生ServletContextEvent事件,因为Tomcat在启动web应用程序时就会创 建一个ServletContext对象 * 会调用监听器的对应事件处理方法contextInitialized()同时会传递事件对象 ServletContextEvent * 5. 程序员可以通过ServletContextEvent事件对象,来获取需要的信息,然后再进行业务处理 * 6. Tomcat通过web.xml文件在使用反射创建相应的监听器对象 */ public class ContextListener implements ServletContextListener { //被创建时调用 @Override public void contextInitialized(ServletContextEvent sce) { ServletContext servletContext = sce.getServletContext(); System.out.println("ServletContext 被创建了" + servletContext); } //被销毁时调用 @Override public void contextDestroyed(ServletContextEvent sce) { ServletContext servletContext = sce.getServletContext(); System.out.println("ServletContext 被销毁了" + servletContext); } }
3.ServletContextAttributeListener监听器
作用:监听ServletContext属性变化
相关方法
import javax.servlet.ServletContextAttributeListener; /**
ClassName:ContextAttributeListener
Package:com.leon.listener
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/9 19:08
@Version: 1.0
*/
public class ContextAttributeListener implements ServletContextAttributeListener {
//属性添加的时候调用
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {System.out.println("ContextAttributeListener attributeAdded 被调用了~~~~"); System.out.println("添加属性了"); System.out.println("添加的属性:" + scae.getName());
}
//属性删除的时候调用
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {System.out.println("ContextAttributeListener attributeRemoved 被调用了~~~~"); System.out.println("替换属性了"); System.out.println("删除的属性:" + scae.getName());
}
//属性替换的时候调用
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {System.out.println("ContextAttributeListener attributeReplaced 被调用了~~~~"); System.out.println("修改属性了"); System.out.println("修改的属性:" + scae.getName());
}
}
4. HttpSessionListener监听
作用:监听Session创建或销毁,即生命周期监听
相关方法
package com.leon.listener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /**
ClassName:SessionListener
Package:com.leon.listener
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/9 19:44
@Version: 1.0
*/
public class SessionListener implements HttpSessionListener {
//创建Session的时候调用
@Override
public void sessionCreated(HttpSessionEvent se) {System.out.println("SessionListener sessionCreated被调用了~~~~"); HttpSession session = se.getSession(); System.out.println("被创建的Session的id是:" + session.getId());
}
//删除Session的时候调用
@Override
public void sessionDestroyed(HttpSessionEvent se) {System.out.println("SessionListener sessionDestroyed被调用了······"); HttpSession session = se.getSession(); System.out.println("被删除的Session的id是:" + session.getId());
}
}使用场景:监控用户上线,离线
5.HttpSessionAttributeListener监听器
作用:监听Session属性的变化
相关方法
package com.leon.listener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; /**
ClassName:SessionAttributeListener
Package:com.leon.listener
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/9 20:01
@Version: 1.0
*/
public class SessionAttributeListener implements HttpSessionAttributeListener {@Override
public void attributeAdded(HttpSessionBindingEvent se) {System.out.println("SessionAttributeListener attributeAdded 属性添加了:--->" + se.getValue());
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {System.out.println("SessionAttributeListener attributeRemoved 属性删除了:--->" + se.getValue());
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {System.out.println("SessionAttributeListener attributeReplaced 属性替换了:--->" + se.getValue());
}
}
6.ServletRequestListener监听器
作用:监听Request创建或销毁,即Request生命周期监听
相关方法
package com.leon.listener; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletRequest; /**
ClassName:RequestListener
Package:com.leon.listener
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/9 20:16
@Version: 1.0
*/
public class RequestListener implements ServletRequestListener{@Override
public void requestInitialized(ServletRequestEvent sre) {System.out.println("Request被创建了"); ServletRequest servletRequest = sre.getServletRequest(); System.out.println(((HttpServletRequest)servletRequest).getRequestURL());
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {System.out.println("Request被销毁了");
}
}使用场景:某个IP访问我们网站的频率,日志,访问资源
7.ServletRequestAttributeListener监听器
作用:Request属性的变化
相关方法
package com.leon.listener; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; /**
ClassName:RequestAttributeListener
Package:com.leon.listener
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/9 20:20
@Version: 1.0
*/
public class RequestAttributeListener implements ServletRequestAttributeListener {@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {System.out.println("Request 的属性添加了");
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {System.out.println("Request 的属性删除了");
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {System.out.println("Request 的属性修改了");
}
}
8.其他监听器
- HttpSessionBindingListener监听器
- HttpSessionActivationListener监听器
二、Filter过滤器
1. 使用过滤器的原因
- 使用传统的每个页面进行验证,会造成代码的冗余,因而功能是重复的,这样不便于维护
- 过滤器可以:统计进行验证,比如权限,身份,日志,事务
2.Filter过滤器的工作原理
3.Filter过滤器的注意事项
Servlet中的请求转发是不会激发过滤器的
在web.xml文件中的注意事项
1.Filter一般是写在其他Servlet的前面 2.通过观察发现Filter与Servlet非常相似,由此可得Filter也是被tomcat管理和维护 3.Filter中的url-pattern标签,就是当你在请求的时候的URL和url-pattern标签中的URL匹配时 就会调用该Filter 4./manage/* 因为是在服务器解析所以第一个"/"会被解析成 http://ip:port/工程路径 5.完整的路径就是http://ip:port/工程路径/manage/* 当请求的URL满足该条件时都会调用该Filter 标签中的解读 <!--ManageFilter--> <filter> <filter-name>ManageFilter</filter-name> <filter-class>com.leon.filter.ManageFilter</filter-class> </filter> <filter-mapping> <filter-name>ManageFilter</filter-name> <!--目录匹配 1.这个"*"表示Mange目录下的任意资源被请求的时候都会被匹配上 2."*"可以表示多成目录,只要是Manage下的子目录即可 --> <url-pattern>/manage/*</url-pattern> </filter-mapping>
Filter过滤器中的doFilter(ServletRequest request,ServletResponse response,FilterChain filterChain)注意事项
filterChain.doFilter(servletRequest, servletResponse); /* 该方法的解析 1.表示可以继续访问目标资源,也可以理解为放行 2.servletRequest和ServletResponse 对象会传递给目标资源或文件 3.目标资源所获取的request和response对象是和Filter所传过来的对象是相同的(指的是同一个 http请求) */
4. Filter过滤器在web.xml文件中的url-pattern
- url-pattern :表示Filter的拦截路径,即浏览器在请求的URL匹配上拦截路径时,过滤器会进行拦截过滤
- 精确匹配< url-pattern >/a.jsp< /url-pattern >对应的匹配请求地址为:http://ip:port/工程路径/a.jsp会被拦截
- 目录匹配 < url-pattern >/manage/*< /url-pattern >对应的匹配请求地址为:http://ip:port/工程路径/manage/xxx,即web工程下的Manage目录下的所有资源都会被拦截
- 后缀名匹配 < url-pattern >.jsp< /url-pattern >后缀名可变,比如 .action *.do对应的匹配请求地址为:http://ip:port/工程路径/xxx.jsp,后缀名为.jsp会被拦截
- 任意匹配 < url-pattern >/< /url-pattern >后缀名可变,比如 .action *.do对应的匹配请求地址为:http://ip:port/工程路径,即web工程下的任意资源都会被拦截
- Filter过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在
5. Filter生命周期的注意事项
- filter在web项目启动时,由tomcat来创建Filter实例,每个Filter只会创建一次Filter实例,如果重启和从新发布则会再次创建,因为之前的Filter实例被清除了
- tomcat会调用Filter默认的无参构造器,同时会调用init方法,每个Filter实例的init方法也只会调用一次
- 在创建Filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入
- 通过FilterConfig对象,程序员可以获取该Filter的相关配置信息
- 当一个http请求和该Filter的url-pattern匹配时,就会调用doFiilter()方法
- 在调用doFilter()方法时,tomcat会同时创建ServletRequest和ServletResponse和FilterChain对象,并通过doFiter()方法传入
- 如果后面的请求目标资源(jsp,servlet….),使用的request和response与前面Filter传递的ServletRequest和ServletResponse的对象是同一个
6.FilterConfig接口
类图
说明
FilterConfig是Filter过滤器的配置类
Tomcat每次创建Filter的时候,也会创建一个FilterConfig对象,这里包含了Filter配置文件的配置信息
FilterConfig对象作用是获取Filter过滤器的配置内容
7. FilterChain注意事项和细节
多个Filter和目标资源在一次http请求,在同一个线程中
当一个请求URL和Filter的url-pattern匹配时,才会被执行,如果有多个匹配上,就会顺序执行,形成一个Filter调用链【这个顺序是你定义在web.xml中Filter的顺序】
多个Filter共同执行时,因为是一次http请求,使用同一request对象
多个Filter执行顺序,和web.xml配置顺序保持一致
filterChain.doFilter(ServletRequest request ,ServletResponse response)方法,将执行下一个过滤器的doFilter()方法,如果后面没有过滤器,则执行目标资源(或文件)
顺序分析(案例)
类1
package com.leon.filter; import javax.servlet.*; import java.io.IOException; /**
ClassName:ChainFilter1
Package:com.leon.filter
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/10 10:52
@Version: 1.0
*/
public class ChainFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("ChainFilter1 前置代码"); filterChain.doFilter(servletRequest,servletResponse); System.out.println("ChainFilter1 后置代码");
}
@Override
public void destroy() {}
}类2
package com.leon.filter; import javax.servlet.*; import java.io.IOException; /** * ClassName:ChainFilter2 * Package:com.leon.filter * Description: * * @Author: leon-->ZGJ * @Create: 2023/11/10 10:53 * @Version: 1.0 */ public class ChainFilter2 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("ChainFilter2 前置代码"); filterChain.doFilter(servletRequest,servletResponse); System.out.println("ChainFilter2 后置代码"); } @Override public void destroy() { } }
执行顺序(在web.xml文件中ChainFilter1定义在ChainFilter2的前面)