Filter过滤器与Listener监听器

- 什么是过滤器Filter?有什么用?

Filter是过滤器,就像泡茶叶时用的过滤网一样,具有过滤功能。再说详细一点,就是拦截+放行功能。过滤网拦截了茶叶,放行了茶水。而过滤器拦截的是请求,放行则表示继续执行接下来的代码。

在JavaWeb中,过滤器可以在Servlet这个目标程序执行之前添加代码,也可以在其之后添加代码。

一般情况下,在过滤器中编写的代码都是公共代码,[eg]每个Servlet执行之前都要判断一下用户是否已经登陆,那么就可以写一个过滤器,过滤器的内容就是判断用户是否登陆。接下来就是如何将过滤器放在Servlet之前了。

如何将过滤器放在目标Servlet之前呢?

很简单,只需保证过滤器的路径包含Servlet的路径即可。假设路径为"/oa/dept"的时候走的是ServletDept,那么过滤器的路径是"/oa/dept"也行,"/oa/*"也行,总之只要是包含目标Servlet的路径即可。这是因为Filter的优先级天生就比Servlet高,所以当访问路径以后,优先走到Filter中,这便是本文第一段所说的“拦截”。在拦截以后,是否放行则取决于一行代码:Chain.doFilter( request , response ); 这行代码的含义为“放行”:继续进入下一个Filter,如果没有Filter了则进入Servlet。

多个Filter如何确定执行顺序?

上一段提到了Chain对象的doFilter方法具有“放行”功能,然后提到了这个“放行”有可能会进入到下一个Filter,那么就有一个新的问题:既然有多个Filter,如何判断他们的执行顺序呢?有两种情况如下:

第一种情况:Filter是在web.xml文件中配置的。那么此时filter-mapping越靠前的,对应的filter优先级越高。

第二种情况:使用@WebFilter注解的,则比较的是类名。类名逐个比对,在字典中排序靠前的则优先级高。例如Filter1优先级高于Filter2,这是因为逐个字母比较的时候,前面都一样,后面“1”在“2”前面,所以先走Filter1.然后FilterA优先级高于FilterB,理由同上。

- Filter怎么写?

说了这么多,Filter究竟该怎么写呢?其实也就两步。

第一步:编写一个类实现一个接口:jakarta.servlet.Filter。并且实现所有方法。这里面有三个方法。

    init方法在Filter对象第一次被创建之后调用,并且只调用一次

    doFilter方法 只要用户发送一次请求,则执行一次,发送N次请求,则执行N次。在这个方法中添加过滤规则

    destroy方法 在Filter对象被释放/销毁之前调用,并且只调用一次

第二步:在web.xml中配置这个Filter,这个配置和Servlet的配置很像。或者用注解@WebFilter代替配置。

- Filter生命周期

和Servlet一样。唯一的区别在于Filter在服务器启动阶段就实例化,但是Servlet不会。

- 责任链设计模式

Filter过滤器这里有一个设计模式:责任链设计模式

核心思想:在程序运行阶段,动态的组合程序的调用顺序

过滤器最大的优点:在编程阶段不会确定调用顺序。因为Filter的调用顺序是配置到web.xml中的,只需要修改配置文件的filter-mapping的顺序就可以调整Filter的执行顺序。显然Filter的执行顺序是在程序运行阶段动态组合的。那么这种设计模式被称为责任链设计模式

- Filter小结

简单小结一下Filter就是过滤器,包含拦截和放行功能。拦截是拦截请求,只要访问路径符合我这个过滤器的路径,我都会拦截住。拦截过后便会按照顺序执行我的三个方法------init方法、doFilter方法、destroy方法。在doFilter方法中如果写Chain.doFilter(request , response); 则表示“放行”。“放行”时候如果有过滤器会先进过滤器,没有过滤器则会进入路径对应的Servlet。

过滤器怎么写呢?先写一个Filter类(需要实现Filter接口),然后重写其中的三个方法,伪代码如下:


@Override

init(){    //初始化方法

    Filter初始化

}

doFilter(这里面有个Chain对象){    

    //doFilter开始执行

    这里可以写希望在进入Servlet之前就进行的处理

    Chain.doFilter(request , response); 这行代码表示“放行”。如果不写这行代码,就拦截住了,流程不往下走了

    这里可以写希望在进入Servlet之后就进行的处理

    //doFilter执行结束

}

destroy(){    //销毁方法

    Filter销毁

}


由上面的伪代码,我们就可以比较清晰的知道我们的处理代码应该写在什么地方了。同时我们也会发现如果有Filter1、Filter2代码都如上所示,然后他们会经过ServletA的话,执行顺序应该是与栈类似:即先进后出

Filter1的doFilter开始执行--->Filter2的doFilter开始执行--->Servlet开始执行-->Servlet执行结束--->Filter2的doFilter执行结束--->Filter1的doFilter执行结束

- 什么是监听器Listener?有什么用?

监听器也是Servlet规范中的一员,这和Filter一样。

监听器可以理解为是触发器。生活中有烟雾触发器,它一旦检测到烟雾的存在,便会发出警报。监听器便是JavaWeb中的“触发器”。监听器会在特殊的时机(烟雾突发)做出行为(报警)。因此程序员不用去手动调用它,因为程序员根本不知道什么时候会是特殊时机,所以只能是等特殊时机发生时,由服务器自动调用相关方法。

所以监听器实际上就是Servlet规范留给程序员的特殊时机。特殊的时机想执行某段代码,就需要能想到对应的监听器。

有哪些监听器呢?

1 ServletContextListener:与下文request类似

2 ServletContextAttributeListener

3 ServletRequestListener:这个里面有两个方法,一个是request对象创建时调用的,一个是request对象销毁时调用的。这两个方法都是有默认值的,所以可以不重写,但是如果想使用这个“特殊时机”来完成特定功能,则可以选择重写

4 ServletRequestAttributeListener:里面有三个方法,分别对应request对象的三个动作:往域中存add、删remove、改replace。当这三个动作发生的时候,监听器里的对应方法就会执行。(有点像触发器,例如烟雾触发器,触发器检测到烟雾的存在,就报警。当request对象发生了这三个动作,对应的方法就被执行。)

5 HttpSessionListener:与上文request类似

6 HttpSessionAttributeListener:该监听器需要使用@WebListener注解进行标注

该监听器监听的是什么?是session域中数据的变化。只要数据变化,则执行相应的方法。主要监测点在session域对象上

7 HttpSessionBindingListener:该监听器不需要使用@WebListener进行标注。因为他是监听类的,不是监听网站的

假设User类实现了该监听器,那么User对象在被放入session的时候就会触发bind事件,User对象从session中被删除的时候就会触发unbind事件

假设Customer类没有实现该监听器,那么Customer对象放入session或者从session删除的时候,不会触发bind和unbind事件

8 HttpSessionIdListener:session的id发生改变的时候,监听器中唯一一个方法就会被调用

9 HttpSessionActivationListener:监听session对象的活化与钝化的

钝化:session对象从内存存储到硬盘文件;活化:session对象从硬盘文件存储到内存

- Listener怎么写?

前六种Listener实现一个监听器的步骤:以ServletContextListener为例。(ServletRequestListener和ServletSessionListener相同)

第一步:编写一个类实现ServletContextListener接口。并且实现里面的两个方法

void contextInitialized ( ServletContextEvent event );

void contextDestroyed ( ServletContextEvent event );

(如果是有Attribute的话,则需实现setAttribute、removeAttribute、replaceAttribute三个方法)

第二步:在web.xml文件中对ServletContextListener进行配置,如下:

<listener>

    <listener-class>com.bjpowernode.javaweb.listener.MyServletContextListener</listener-class>

</listener>

当然,可以用@WebListener代替配置文件


HttpSessionBindingListener:这个是在普通Java实例类中实现的,实现HttpSessionBindingListener接口后需要重写两个方法:valueBound(数据绑定)和valueUnbound(数据解绑)。在之后调用session域对象使用到该Java实例类的时候,就会触发绑定事件。(这里讲的有点抽象,在后边小结内会有例子说明)

- Listener小结

以上的列举看起来比较复杂,但其实是有规律可循的:前面六种监听器,实际上是对应三个域。request域、session域、context域。因此这六种监听器中不带Attribute的三种监听器分别监听的是三个域的状态,带Attribute的三种监听器分别监听的是三个域中所存取的属性的状态。以context举例:


不带Attribute:监听的是context对象的状态

contextInitialized ( ServletContextEvent event ){

    context初始化的时候则执行这里的代码。换句话说就是想让context初始化的时候执行的代码就放在这里

}

contextDestroyed ( ServletContextEvent event ){

        context销毁的时候则执行这里的代码。换句话说就是想让context销毁的时候执行的代码就放在这里

}


带Attribute:监听的是context对象域中存取数据的状态

attributeAdded (){

    往域中添加的时候执行这里的代码。换句话说就是想在域添加东西这个时刻执行的代码就往这里写

}

attributeRemoved (){

    往域中删除的时候执行这里的代码。换句话说就是想在域删除东西这个时刻执行的代码就往这里写

}

attributeReplaced (){

    往域中替换的时候执行这里的代码。换句话说就是想在域替换东西这个时刻执行的代码就往这里写

}


HttpSessionBindingListener:

某类中{

    valveBound(){

        绑定 的时候执行这里

    }

    valueUnbound(){

        解绑 的时候执行这里

    }

}


HttpSessionBindingListener与HttpSessionAttributeListener的区别:前者是使用在类当中,每当与这个类有关的时候触发。后者是不使用在普通实例类当中,只在session域中加减东西的时候触发。就好比session域是一个篮子🧺,然后现在有个苹果类实现了HttpSessionBindingListener接口。那么往篮子🧺中加一个梨🍐的时候就会触发后者,往篮子🧺里加苹果🍎则两者都会触发。所以两者关注的点不一样,前者关注苹果🍎,后者关注篮子🧺。注意:前者(苹果🍎)是只有往session域当中放才会触发奥。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容