欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java 监听器Listener和过滤器Filter 原理分析

程序员文章站 2024-01-11 16:02:34
Listener & FilterListener监听器,能做什么事?监听某一个事件的发生,状态的改变。监听器的内部原理:其实就是接口回调。1、接口回调需求:A在执行循环,当循环到5的时候,通知B。事先先把一个对象传递给 A,当A 执行到5的时候,通过这个对象,来调用B中的方法。注意,不是直接传递B的实例,而是传递一个接口的实例过去。2、Web监听器总共有8个,划分成三种类型:3 + 3 + 2ServletContextListenerServletRequestL...

Listener & Filter

Listener

监听器,能做什么事?
监听某一个事件的发生,状态的改变。

监听器的内部原理:其实就是接口回调


1、接口回调

需求:A在执行循环,当循环到5的时候,通知B。

事先先把一个对象传递给 A,当A 执行到5的时候,通过这个对象,来调用B中的方法。
注意,不是直接传递B的实例,而是传递一个接口的实例过去。

Java 监听器Listener和过滤器Filter 原理分析


2、Web监听器

总共有8个,划分成三种类型:3 + 3 + 2

ServletContextListener
ServletRequestListener
HttpSessionListener

ServletContextAttributeListener
ServletRequestAttributeListener
HttpSessionAttributeListener

HttpSessionBindingListener
HttpSessionActivationListener

如何创建监听器?

  • 定义一个类,实现接口
  • 注册 | 配置监听器

3、第一类:监听三个作用域创建和销毁。

哪三个作用域?
request — httpServletRequest
session — httpSession
application — ServletContext

(1)监听ServletContext创建销毁:ServletContextListener

servletContext创建:启动服务器。
servletContext销毁:关闭服务器,或者从服务器移除项目。

(2)监听request创建销毁:ServletRequestListener

request创建:访问服务器上的任意资源都会有请求出现。
例如:访问jsp,html,servlet等。
request销毁:服务器对这次请求作出了响应后。

测试代码:

public class MyRequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) { System.out.println("servletrequest 销毁了"); } @Override public void requestInitialized(ServletRequestEvent sre) { System.out.println("servletrequest 初始化了"); } } 

在web.xml中注册监听器的代码:

<listener> <listener-class>com.itheima.listener.MyRequestListener</listener-class> </listener> 

(3)监听session创建销毁:HttpSessionListener

session创建:只要调用getSession

访问html:不会创建session。
访问jsp:会,jsp中9个有内置对象,其中就包括了session。
访问servlet:会创建session。

session销毁:超时,默认是30分钟。

服务器非正常关闭,销毁session。
正常关闭服务器(序列化)。

测试代码:

public class MySessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("创建session了"); } @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("销毁session了"); } } 

(4)监听三个作用域创建销毁的作用:

ServletContextListener的作用:
在servletcontext创建的时候,完成自己想要的初始化工作
执行自定义任务调度,执行某一个任务。

ServletRequestListener很少用到,来了数据请求服务器本身就知道。

HttpSessionListener的作用:
统计在线人数。


4、第二类:监听三个作用域属性状态变更

可以监听在作用域中值, 添加 | 替换 | 移除的动作。

(1)servletContext — ServletContextAttributeListener
Java 监听器Listener和过滤器Filter 原理分析

(2)request — ServletRequestAttributeListener
Java 监听器Listener和过滤器Filter 原理分析

(3)session — HttpSessionAttributeListener
Java 监听器Listener和过滤器Filter 原理分析
这三个接口中的方法都类似,都是属性值添加,替换,移除状态。


5、第三类:监听httpSession

(1)HttpSessionBindingListener
监听httpSession里面存值的状态变更,这一类监听器不用注册。

监听对象与session 绑定 和 解除绑定 的动作。
跟第二类中监听session属性添加,移除类似。

测试代码:

public class MyHttpSessionBindingListener implements HttpSessionBindingListener { @Override public void valueBound(HttpSessionBindingEvent event) { System.out.println("对象被绑定进来了"); } @Override public void valueUnbound(HttpSessionBindingEvent event) { System.out.println("对象被解除绑定"); } } 

(2)HttpSessionActivationListener
用于监听现在session的值 是 钝化 (序列化)还是活化 (反序列化)的动作。

什么是钝化(序列化):把内存中的数据存储到硬盘上。
什么是活化(反序列化):把硬盘中的数据读取到内存中。

session的钝化,活化的用意何在?
session中的值可能会很多, 并且我们有很长一段时间不使用这个内存中的值。
那么可以考虑把session的值可以存储到硬盘上。【钝化】
等下一次在使用的时候,在从硬盘上提取出来。【活化】

如何让session的在一定时间内自动钝化?
做配置即可,三种手法:

  • 1、在tomcat里面 conf/context.xml 里面配置。
    范围:对所有的运行在这个服务器的项目生效。

  • 2、在conf/Catalina/localhost/context.xml 配置。
    范围:对 localhost生效。localhost:8080。

  • 3、在自己的web工程项目中的 META-INF/context.xml。这种配置方式是常用的。
    范围:只对当前的工程生效。

在META-INF下文件配置内容如下:

<Context> <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"> <Store className="org.apache.catalina.session.FileStore" directory="itheima"/> </Manager> </Context> 

参数如下:
maxIdleSwap:单位是分钟,几分钟内没用到就钝化。
directory:钝化后的那个文件存放的目录位置,钝化后存到tomcat对应工程文件中。

上述钝化到 D:\tomcat\apache-tomcat-7.0.52\work\Catalina\localhost\ListenerDemo\itheima





Filter(重点)

过滤器,其实就是对客户端发出来的请求进行过滤。

浏览器发出,在中间就可以过滤,然后服务器派servlet处理。
其实过滤器起到的是过滤拦截的作用。

常用功能作用:
对一些敏感词汇进行过滤。
统一设置编码。
自动登录。

Filter的生命周期:
创建:服务器启动的时候就创建。
销毁:服务器停止的时候就销毁。


1、如何创建Filter

(1)先定义一个类,实现Filter

public class FilterDemo implements Filter { public void destroy() { System.out.println("服务器关闭,过滤器销毁了。。。"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("来到过虑器了。。。"); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { System.out.println("服务器启动,过滤器创建了。。。"); } } 

(2)然后注册过滤器

在web.xml里面注册,注册的手法与servlet基本一样。

注册代码内容:

<filter> <filter-name>FilterDemo</filter-name> <filter-class>com.itheima.filter.FilterDemo</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 

2、Filter执行顺序

(1)客户端发出请求,先经过过滤器,如果过滤器放行,那么才能到servlet服务器。

(2)如果有多个过滤器,那么他们会按照注册的映射顺序 来排队。
只要有一个过滤器不放行,进行拦截,那么后面排队的过滤器以及servlet都不会收到请求。

(3)服务器响应信息也会经过过滤器,不过不会进行拦截而已,毕竟是服务器过来的数据。


3、Filter中的一些细节

(1)init方法的参数 FilterConfig , 可以用于获取filter在注册的名字,以及初始化参数。

其实这里的设计的初衷与ServletConfig是一样的。

(2)如果想放行,那么在doFilter 方法里面操作,使用参数 chain。

chain.doFilter(request, response); // 放行

(3)<url-pattern>/*</url-pattern>写法格式与servlet一样。

  • 全路径匹配,以 / 开始。
    例如:/LoginServlet,只有访问这个路径才会匹配。

  • 以目录匹配,以 / 开始,以 * 结束。
    例如:/demo01/*,只有访问demo01下的页面,才会匹配。

  • 以后缀名匹配,以 * 开始,以后缀名结束。
    例如:.jsp,.html,只有后缀名匹配上就行。

(4)针对注册中filter-mapping中 dispatcher 设置

REQUEST:只要是请求过来,都拦截,默认就是REQUEST。
FORWARD:只要是转发都拦截。
ERROR:页面出错发生跳转。
INCLUDE:包含页面的时候就拦截。

如果想要设置多个值,用 | 连接值即可(但一般不会这么做)
例如:<dispatcher>REQUEST | FORWARD</dispatcher>


例题:自动登录

1、需求分析

Java 监听器Listener和过滤器Filter 原理分析

2、搭建环境

搭建数据库
搭建页面

3、登录servlet代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String userName = request.getParameter("username"); String password = request.getParameter("password"); String autoLogin = request.getParameter("auto_login"); UserBean user = new UserBean(); user.setUsername(userName); user.setPassword(password); UserDao dao = new UserDaoImpl(); UserBean userBean = dao.login(user); if(userBean != null){ //成功了,进入首页 request.getSession().setAttribute("userBean", userBean); response.sendRedirect("index.jsp"); }else{ //不成功... request.getRequestDispatcher("login.jsp").forward(request, response); } } catch (SQLException e) { e.printStackTrace(); } } 
4、过滤器

过滤器的核心不是完成拦截不给,还是放行显示。
它的核心是在放行之前,帮用户完成登录的功能。

实现思路:
(1)先判断session是否有效,如果有效,就不用取cookie了,直接放行。

(2)如果session失效了,那么就再取cookie。
没有cookie,放行。
有cookie:

  • 取出来cookie的值,然后完成登录。
  • 把这个用户的值存储到session中,再放行。

过滤器代码:

public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { // 强制向下转型,不然无法获取cookies HttpServletRequest request = (HttpServletRequest) req; //先判断,现在session中还有没有那个userBean. UserBean userBean = (UserBean) request.getSession().getAttribute("userBean"); //session中数据有效 if(userBean != null){ chain.doFilter(request, response); }else{ //代表session失效了。 //2. 看cookie。 //1. 来请求的时候,先从请求里面取出cookie , 但是cookie有很多的key-value Cookie[] cookies = request.getCookies(); //2. 从一堆的cookie里面找出我们以前给浏览器发的那个cookie Cookie cookie = CookieUtil.findCookie(cookies, "auto_login"); //第一次来 if(cookie == null){ chain.doFilter(request, response); }else{ //不是第一次 String value = cookie.getValue(); String username = value.split("#itheima#")[0]; String password = value.split("#itheima#")[1]; //完成登录 UserBean user = new UserBean(); user.setUsername(username); user.setPassword(password); UserDao dao = new UserDaoImpl(); userBean = dao.login(user); //使用session存这个值到域中,方便下一次未过期前还可以用。 request.getSession().setAttribute("userBean", userBean); chain.doFilter(request, response); } } } catch (Exception e) { e.printStackTrace(); chain.doFilter(req, response); } } 
5、BeanUtils的使用

测试代码:

 //注册自己的日期转换器 ConvertUtils.register(new MyDateConverter(), Date.class); //转化数据 Map map = request.getParameterMap(); UserBean bean = new UserBean(); //转化map中的数据,放置到bean对象身上 BeanUtils.populate(bean, map); 




总结

Listener

8个监听对象:3 + 3 + 2

分三种类型:
针对三个作用域的创建和销毁。
针对三个作用域的值改变 ,添加 | 替换 | 移除。
针对session中的值,绑定 解绑,钝化 活化。

钝化 ( 序列化 ) :内存中的对象存储到硬盘。
活化 ( 反序列化 ) :硬盘中的文件读取到内存。

超时失效,session销毁了,更别提其数据。
非正常关闭服务器,session数据钝化。正常关闭服务器,销毁。

设置了session,多久时间自动钝化。context.xml文件。

ServletContextListner:应用被部署的时候,服务器加载这个项目的时候,做一些初始化工作, 任务调度。
HttpSessionListener:统计在线人数。
HttpSessionActivationListener:钝化,活化处理。


Filter

使用频率更高

如果要写一个过滤器,步骤:

  • 定义一个类,实现接口 Filter。

  • 注册web.xml,与注册servlet相似。

过滤器放行:
chain.doFilter(request, response);

过滤器生命周期:
创建:启动服务器。
销毁:关闭服务器,或者从服务器中移除项目。

为什么过滤器在开启服务器就创建,而不是来了一次请求再创建?
过滤器的创建可能需要一定时间,如果来了一次请求再创建,用户体验不好。


本文地址:https://blog.csdn.net/pipizhen_/article/details/108248183