监听器与过滤器的区别,及执行规律与顺序
做了一个简单的测试,顺便让自己也深入了解了解。
话不多说,先创建类文件---new---class---add 输入要实现的接口
监听器大致分为三种级别的接口:
分别时 request session ServletContext
下面弄个小测试,顺便看看执行的顺序与区别和之间的联系
request 声明周期太短,ServletContext生命周期又太长,还是用session,不短不长正好符合今天的测试
首先创建 一个类 sessionCreate 实现 HttpSessionListener 这个接口 的Create() 方法和Destroyed()方法
再配置web.xml文件
再创建一个类 sessionUpdate 实现 HttpSessionAttributeListener 接口的 Added() ,Removed() ,Replaced() 方法
省略配置步骤,基本上一样,只是包名与文件名的不同而已。
在创建过滤器,实现Filter 接口,跟上面创建监听器步骤基本一致
下面配置文件过滤器,基本上常用的是过滤页面的字符编码,还有登入权限的管理
如上图,<url-pattern>/login/*</url-pattern> 时指过滤login文件夹下的所有文件,当然也可以指定某个页面,不过我通常用这种方法,原因呢?好用呗,(后面具体会讲)
基本配置搞定,创建一个Entity实体类,用来储存数据,方便之后的展示数据,有个明确直观的效果,
接着在 sessionCreate 类中的 Create() 方法写上 System.out.println("创建session"); 输出语句,方便在控制台看到程序执行的顺序
省略其他几个方法和数据库 编写与配置步骤.....
编写index.jsp 页面
准备完成,然后在 tomcat 部署项目 ,点击调试,在每个方法中打上断点,运行,发现:
1.当服务运行时,就已经被实例化并执行FilterServlet 的 init() 方法
2.由于我的过滤页面时在login包下的,当执行index.jsp 页面时,index.jsp不在login包下,则不会执行Filter接口的doFilter()方法
然后在打开浏览器输入项目的 url
之后我又尝试以不同的浏览器打开,然后关闭,发现紧接着后面输入了一句 创建session,从而可以说明,当服务器开启之后,
3.每打开一个新的会话, sessionCreate 类中的 Create() 方法会被调用一次,
而关闭浏览器却没有 输出session被销毁,为什么呢?翻看其他的资料,发现: 除了手动的设置session 的最大非活动时间,或者立即销毁,在tomcat的conf文件的web.xml文件默认设置了session非活动的最长时效,默认30分钟
然后输入账号密码,进行登入-------------------------------------------------------------------
还没有进去登入成功的页面
Console 输出这样的结果:
这说明:
3.Servlet 首先被实例化,然后初始化,在根据form表单提交的方式执行 doPost()方法或doGet()方法,通常表单提交都是doPost(),我这里提交方式就用doPost()
紧接着 在superManagerServlet 这个过滤页面(处理数据与逻辑) 输出了System.out.println("servlet的doPost方法被执行");
调用查询方法查询数据库信息,实例化实体类对象去储蓄用户输出的数据,把用户数据保存到session里面,通过session.setAttribute("user", user);保存到session 域中,
结果一直都没有输出 System.out.println("添加session用户信息");为什么呢?原来,我保存的user 用户信息为null,导致没有执行session.setAttribute("user", user); 当session调用set 方法保存数据时,当数据为null 时,就会出现设置的数据为空,(我想是不是session底层的数据处理,为节省减少服务器的压力,session底层下时怎么处理数据的还有待研究)
弄好之后如图:
4.session.setAttribute() 设置储存数据时,会调用HttpSessionAttributeListener这个接口下的 attributeAdded()方法
5.保存完数据之后,程序又走到 Filter接口类的的doFilter()方法中,去执行页面过滤
这就是我在web.xml配置 filter 文件时 获取文件路径 /login/* 包下的原因了,当执行index.jsp 页面时,因为不在 这个login包下,则不会去过滤index.jsp页面,不然你也可以试试(会报错误,重定向次数过多,除非你就过滤页面字符的编码,不过这样就没必要使用这个过滤器了,还不如直接在页面用小代码块直接写request设置字符编码.....)
根据业务需求,进行逻辑判断显示登入之后的页面
当设置了session的最大非活动时间,这些基本流程走完之后就是默默的等待session的失效了
6.当设置了session 的有效时长之后,会先执行HttpSessionListener 接口的 Destroyed() 方法 销毁session,这里的销毁不是真正意义上的销毁,只是让数据为空(说错了请谅解,只是我对这个方法的个人理解)
当执行 Destroyed() 这个方法之后
7.再执行HttpSessionAttributeListener 这个接口的Removed()方法去真正意思上的销毁(删除)
哦,对了,还有一个方法没有讲到,就是HttpSessionAttributeListener 这个接口的Replaced()方法,那么他会在什么时候被执行呢?
再打开另外一个浏览器去测试
如图:
从图中我们可以清晰的看到Console 的输出结果以及执行顺序
第一个浏览器打开之后创建session之后和第二个浏览器打开之后创建session之后都是执行HttpSessionAttributeListener的 Added()而没有执行Replaced()方法,
因为浏览器打开之后产生唯一的sessionid,而浏览器不同产生的sessionid 也不同,session都是通过这个唯一标识去操作数据的
那么什么时候会执行 Replaced()方法呢?
再次测试(以Google为例),我登入账号密码之后,再关闭浏览器再打开Google,再次登入
Console的输出结果如下
看到输出结果,大家就应该明白了把?我通过session.setAttribute("user", user);设置的用户信息,再次被调用session设置保存数据时,则会调用HttpSessionAttributeListener的Replaced()方法
也就是说,set的对象名相同则会调用Replaced去替换原来的session对象
这就是基本的监听器与过滤器的执行流程
servlet过滤器的生命周期:
服务开启时实例化
->初始化
->浏览器发送请求
->访问公共service方法,而当每次向服务器发送请求页面时,则会调用doFilter()方法去执行页面的过滤
->访问私有servlet方法
->调用doGetI()/doPost()
->当关闭服务器的时候就会调用destroy方法销毁过滤器。
ServletSession监听器的生命周期:
->打开浏览器时(创建session对象,生成唯一sessionid)
->使用setAttribute保存属性时
->调用add()
->重复设置session的对象时则会调用Replaced()方法
->设置非活动时长/默认有效时长
->调用 Destroyed() 方法 销毁session
->Removed()删除session
区别:
过滤器:
1.当服务器接受请求时被触发,初始化一次
2.服务器加载时就已经加载成功了,时时刻刻等待服务器的响应
3.只有当你的web应用停止或重新部署的时候才销毁
4.公有实现的接口Filter 私有:HttpServlet
监听器,以session为例:
1.服务器加载完毕,产生一个新的会话时(当然别的对象还没又尝试过,不过我想的时,服务器启动完毕之后它才会被启动把)
2.当对象的属性被修改时触发时
3.Servlet的监听器Listener的九大接口
联系:
过滤器Filter 依赖于Servlet容器,基于回调函数,过滤范围大
作用:
过滤器:主要用于,业务逻辑的页面跳转处理和字符编码设置,减轻服务器负载,压力
监听器:主要用于,做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等
配置问题:
过滤器执行的顺序是按照,web.xml中filter-mapping标签的书写顺序执行(从上往下执行,不确定,自己没测试过,改天有机会测试)
共同点: 监听器、过滤器一般配置在web.xml中
不同点: 一个应用中可以配置多个过滤器,而监听器时对应的实现接口
执行顺序:
创建: 监听器-->过滤器-->Servlet.
销毁: 过滤器-->Servlet-->监听器
大致上就是这样,如有不对之处,批评指正,虚心求教.....