一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - 詳解JavaWeb中的 Listener

詳解JavaWeb中的 Listener

2020-06-18 11:29南唐三少 JAVA教程

JavaWeb里面的listener是通過(guò)觀察者設(shè)計(jì)模式進(jìn)行實(shí)現(xiàn)的。下面通過(guò)本文給大家詳細(xì)介紹javaweb中的listener,感興趣的朋友一起看看吧

一、基本概念

JavaWeb里面的listener是通過(guò)觀察者設(shè)計(jì)模式進(jìn)行實(shí)現(xiàn)的。對(duì)于觀察者模式,這里不做過(guò)多介紹,大概講一下什么意思。

觀察者模式又叫發(fā)布訂閱模式或者監(jiān)聽(tīng)器模式。在該模式中有兩個(gè)角色:觀察者和被觀察者(通常也叫做主題)。觀察者在主題里面注冊(cè)自己感興趣的事件,當(dāng)這個(gè)事件發(fā)生時(shí),主題會(huì)通過(guò)回調(diào)接口的方式通知觀察者。

舉個(gè)生活中的例子:訂閱報(bào)紙。任何一個(gè)家庭或個(gè)人都可以向報(bào)社訂閱報(bào)紙。這里報(bào)社就是“主題”,家庭就是“觀察者”。比如家庭需要訂閱明天早晨的報(bào)紙,這個(gè)就是“事件”。到了第二天早晨,報(bào)紙生產(chǎn)出來(lái)了,這個(gè)就是“事件發(fā)生”。當(dāng)事件發(fā)生時(shí),送報(bào)員將報(bào)紙送到家庭的信箱里面,這里的信箱就是“回調(diào)接口”。

詳解JavaWeb中的 Listener

對(duì)于JavaWeb里面的監(jiān)聽(tīng)器,Servlet規(guī)范定義了一些列的Listener接口類(lèi),通過(guò)接口類(lèi)的方式將事件暴露給應(yīng)用程序,應(yīng)用程序如果想監(jiān)聽(tīng)其感興趣的事件,那么不必去直接注冊(cè)對(duì)應(yīng)的事件,而是編寫(xiě)自己的listener實(shí)現(xiàn)相應(yīng)的接口類(lèi),并將自己的listener注冊(cè)到servlet容器。當(dāng)程序關(guān)心的事件發(fā)生時(shí),servlet容器會(huì)通知listener,回調(diào)listener里面的方法。這里自定義的listener就是觀察者,servlet容器就是主題。

詳解JavaWeb中的 Listener

二、樣例分析

上面說(shuō)了,servlet容器是通過(guò)Listener接口類(lèi)將事件暴露給應(yīng)用程序的。所以我們與其說(shuō)是注冊(cè)事件,不如說(shuō)是注冊(cè)監(jiān)聽(tīng)器。對(duì)應(yīng)到編程步驟就是:1.編寫(xiě)自己的listener,實(shí)現(xiàn)特定的Listener接口。2.在web.xml里面注冊(cè)自己的listener。這里以最簡(jiǎn)單的監(jiān)聽(tīng)器接口ServletContextListener舉例:

1.TestListener.java

?
1
2
3
4
5
6
7
8
9
public class TestListener implements ServletContextListener {
public TestListener() {}
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContextListener.contextInitialized");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContextListener.contextDestroyed");
}
}

2.web.xml

?
1
2
3
<listener>
<listener-class>com.nantang.listener.TestListener</listener-class>
</listener>

當(dāng)容器啟動(dòng)時(shí)會(huì)向日志中輸出"ServletContextListener.contextInitialized",當(dāng)容器關(guān)閉時(shí)會(huì)輸出"ServletContextListener.contextDestroyed"。詳細(xì)的解釋后面會(huì)進(jìn)一步分析。

這里需要注意是,如果在IDE(Eclipse、STS等)演示上面的例子,當(dāng)啟動(dòng)服務(wù)器時(shí),在控制臺(tái)可以看到"ServletContextListener.contextInitialized",當(dāng)關(guān)閉服務(wù)器時(shí),是看不到"ServletContextListener.contextDestroyed"的。這不是沒(méi)有執(zhí)行contextDestroyed方法,而是IDE實(shí)現(xiàn)的不夠完美。要想驗(yàn)證確實(shí)調(diào)用了contextDestroyed,可以在contextDestroyed里面寫(xiě)一段代碼邏輯往文件輸出內(nèi)容而不要輸出到控制臺(tái)。

三、源碼分析

現(xiàn)在我們分析下,servlet規(guī)范為我們定義了哪些事件。更準(zhǔn)確的說(shuō)是定義了哪些監(jiān)聽(tīng)接口。下面的介紹都是以servlet3.0規(guī)范為準(zhǔn)。

servlet3.0為我們提供了8個(gè)監(jiān)聽(tīng)器接口,按照它們的作用域來(lái)劃分的話(huà)可以分為三類(lèi):

1.servlet上下文相關(guān)監(jiān)聽(tīng)接口,包括:ServletContextListener和ServletContextAttributeListener。

2.http session相關(guān)監(jiān)聽(tīng)接口,包括:HttpSessionListener、HttpSessionActivationListener、HttpSessionAttributeListener和HttpSessionBindingListener。

3.servlet request相關(guān)監(jiān)聽(tīng)接口,包括:ServletRequestListener和ServletRequestAttributeListener。

其實(shí)從接口的命名,各位看官應(yīng)該能猜出其基本功能。下面我們按分類(lèi)來(lái)解釋。

1.servlet上下文相關(guān)監(jiān)聽(tīng)接口

之前在介紹Servlet的時(shí)候,我們解釋過(guò)一個(gè)web應(yīng)用對(duì)應(yīng)一個(gè)servlet上下文。所以ServletContextListener和ServletContextAttributeListener監(jiān)聽(tīng)的事件的生命范圍是貫穿整個(gè)web應(yīng)用的。下面是這兩個(gè)接口的類(lèi)圖層級(jí)關(guān)系。

詳解JavaWeb中的 Listener

1.1 EventListener

EventListener是一個(gè)標(biāo)記接口,所有的事件監(jiān)聽(tīng)器都必須繼承這個(gè)接口,這就是servlet規(guī)范,沒(méi)什么好解釋的。

1.2 EventObject

和EventListener類(lèi)似,EventObject是個(gè)事件頂級(jí)類(lèi),所有具體的事件類(lèi)都必須繼承EventObject。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class EventObject implements java.io.Serializable {
protected transient Object source;
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
public Object getSource() {
return source;
}
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}

這個(gè)類(lèi)很簡(jiǎn)單,其本質(zhì)就一個(gè)東西:source。通過(guò)類(lèi)名EventObject和屬性名source,就能看出這個(gè)類(lèi)就干了一件事,持有“事件源對(duì)象”。

1.3 ServletContextEvent

?
1
2
3
4
5
6
7
8
public class ServletContextEvent extends java.util.EventObject {
public ServletContextEvent(ServletContext source) {
super(source);
}
public ServletContext getServletContext () {
return (ServletContext) super.getSource();
}
}

servlet上下文事件,這個(gè)事件類(lèi)就是對(duì)EventObject的簡(jiǎn)單繼承。構(gòu)造方法中提供ServletContext實(shí)例作為事件源。因?yàn)槭录词莝ervlet上下文,所以提供個(gè)getServletContext獲取ServletContext實(shí)例。

在我們后續(xù)講解其他事件類(lèi)的時(shí)候,都是一個(gè)模子,每個(gè)事件類(lèi)都提供相應(yīng)的構(gòu)造方法,傳入相應(yīng)的事件源對(duì)象,并提供額外的獲取事件源方法。所以EventObject就是個(gè)事件源的基類(lèi),所有事件子類(lèi)的本質(zhì)就干了一件事,確定具體的事件源對(duì)象。

所以我們后面講解事件的地方,一帶而過(guò)。

1.4 ServletContextListener

?
1
2
3
4
public interface ServletContextListener extends EventListener {
public void contextInitialized ( ServletContextEvent sce );
public void contextDestroyed ( ServletContextEvent sce );
}

servlet上下文監(jiān)聽(tīng)器接口,對(duì)應(yīng)著兩個(gè)事件:servlet上下文初始化事件和servlet上下文即將關(guān)閉事件。

當(dāng)web應(yīng)用初始化的時(shí)候,servlet容器會(huì)構(gòu)造ServletContextEven實(shí)例,并回調(diào)contextInitialize方法。

當(dāng)servlet上下文即將關(guān)閉時(shí),一般是關(guān)閉服務(wù)器之前,servlet容器會(huì)構(gòu)造ServletContextEven實(shí)例,并回調(diào)contextDestroyed方法。這里需要注意的是,contextDestroyed方法的執(zhí)行會(huì)在所有的servlet和filter執(zhí)行完destroy方法之后。

所以如果我們想在應(yīng)用啟動(dòng)或關(guān)閉時(shí)需要做些事情的話(huà),就編寫(xiě)自己的listener實(shí)現(xiàn)該接口。

所有的事件監(jiān)聽(tīng)器也是一個(gè)模子,按照servlet規(guī)范定義相應(yīng)的事件回調(diào)接口方法,方法的入?yún)⒕褪窍鄳?yīng)的事件源實(shí)例。所以我們后面講解監(jiān)聽(tīng)器的地方也一帶而過(guò)。

1.5 ServletContextAttributeEvent

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ServletContextAttributeEvent extends ServletContextEvent {
private String name;
private Object value;
public ServletContextAttributeEvent(ServletContext source, String name, Object value) {
super(source);
this.name = name;
this.value = value;
}
public String getName() {
return this.name;
}
public Object getValue() {
return this.value;
}
}

ServletContextAttributeEvent表示servlet上下文屬性相關(guān)事件,一般當(dāng)屬性發(fā)生改變時(shí)會(huì)觸發(fā)該事件。這個(gè)類(lèi)繼承ServletContextEven,事件源也是ServletContext實(shí)例。額外提供屬性名和屬性值的獲取方法。

1.6 ServletContextAttributeListener

?
1
2
3
4
5
public interface ServletContextAttributeListener extends EventListener {
public void attributeAdded(ServletContextAttributeEvent scab);
public void attributeRemoved(ServletContextAttributeEvent scab);
public void attributeReplaced(ServletContextAttributeEvent scab);
}

當(dāng)servlet上文屬性發(fā)生增、刪、改的時(shí)候,servlet容器構(gòu)造ServletContextAttributeEvent事件對(duì)象,分別回調(diào)attributeAdded、attributeRemoved、attributeReplaced方法。

這里需要注意的是attributeReplaced方法,當(dāng)屬性的值被替換的時(shí)候回調(diào)。這個(gè)時(shí)候如果調(diào)用ServletContextAttributeEvent.getValue()方法返回的是替換之前的屬性值。

2 http session相關(guān)監(jiān)聽(tīng)接口

詳解JavaWeb中的 Listener

2.1 HttpSessionEvent

?
1
2
3
4
5
6
7
8
public class HttpSessionEvent extends java.util.EventObject {
public HttpSessionEvent(HttpSession source) {
super(source);
}
public HttpSession getSession () {
return (HttpSession) super.getSource();
}
}

http session相關(guān)事件,當(dāng)session發(fā)生變化時(shí)會(huì)觸發(fā)該事件。事件源是HttpSession實(shí)例,并提供額外的HttpSession獲取方法。

2.2 HttpSessionListener

?
1
2
3
4
public interface HttpSessionListener extends EventListener {
public void sessionCreated ( HttpSessionEvent se );
public void sessionDestroyed ( HttpSessionEvent se );
}

當(dāng)session被創(chuàng)建和銷(xiāo)毀的時(shí)候,servlet容器構(gòu)造HttpSessionEvent事件對(duì)象,并回調(diào)sessionCreated和sessionDestroyed方法。

2.3 HttpSessionActivationListener

?
1
2
3
4
public interface HttpSessionActivationListener extends EventListener {
public void sessionWillPassivate(HttpSessionEvent se);
public void sessionDidActivate(HttpSessionEvent se);
}

當(dāng)session將要鈍化或已被激活時(shí),servlet容器構(gòu)造HttpSessionEvent事件對(duì)象,回調(diào)sessionWillPassivate和sessionDidActivate方法。

這里解釋下鈍化和激活:鈍化是指服務(wù)器內(nèi)存不夠了或者session的活動(dòng)超時(shí)時(shí)間到了,把最近不活動(dòng)的session序列化到磁盤(pán)。激活是指某個(gè)鈍化的session又被訪(fǎng)問(wèn)了,從磁盤(pán)將session反序列化到內(nèi)存。

這里可以看出要想鈍化和激活,首先session得可序列化和反序列化。同時(shí)我們?cè)诰幊踢^(guò)程中,session盡量用String、Integer等簡(jiǎn)單的對(duì)象,盡量不要用list、map等集合。

2.4 HttpSessionBindingEvent

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class HttpSessionBindingEvent extends HttpSessionEvent {
private String name;
private Object value;
public HttpSessionBindingEvent(HttpSession session, String name) {
super(session);
this.name = name;
}
public HttpSessionBindingEvent(HttpSession session, String name, Object value) {
super(session);
this.name = name;
this.value = value;
}
public HttpSession getSession () {
return super.getSession();
}
public String getName() {
return name;
}
public Object getValue() {
return this.value;
}
}

http session的屬性相關(guān)事件,當(dāng)session屬性發(fā)生變化時(shí)會(huì)觸發(fā)該事件。事件源是HttpSession實(shí)例,并提供額外的獲取HttpSession、屬性名、屬性值的方法。

2.5 HttpSessionAttributeListener

?
1
2
3
4
5
public interface HttpSessionAttributeListener extends EventListener {
public void attributeAdded ( HttpSessionBindingEvent se );
public void attributeRemoved ( HttpSessionBindingEvent se );
public void attributeReplaced ( HttpSessionBindingEvent se );
}

當(dāng)session屬性發(fā)生增、刪、改的時(shí)候,servlet容器構(gòu)造HttpSessionBindingEvent事件對(duì)象,分別回調(diào)attributeAdded、attributeRemoved、attributeReplaced方法。

這里需要注意的是attributeReplaced方法,當(dāng)屬性的值被替換的時(shí)候回調(diào)。這個(gè)時(shí)候如果調(diào)用ServletContextAttributeEvent.getValue()方法返回的是替換之前的屬性值。

當(dāng)調(diào)用session的invalidate方法或者session失效時(shí),也會(huì)回調(diào)attributeRemoved方法。

2.6 HttpSessionBindingListener

?
1
2
3
4
public interface HttpSessionBindingListener extends EventListener {
public void valueBound(HttpSessionBindingEvent event);
public void valueUnbound(HttpSessionBindingEvent event);
}

這個(gè)監(jiān)聽(tīng)器也是監(jiān)聽(tīng)session的屬性變化。當(dāng)session屬性發(fā)生增和刪,也就是屬性值綁定和屬性值解綁的時(shí)候,servlet容器構(gòu)造HttpSessionBindingEvent事件對(duì)象,分別回調(diào)valueBound、valueUnbound方法。

這么一看和HttpSessionAttributeListener沒(méi)什么區(qū)別,其實(shí)不是這樣。兩者有個(gè)本質(zhì)的區(qū)別就是事件觸發(fā)的條件。

當(dāng)session的屬性有任何的變化,servlet容器都會(huì)通知HttpSessionAttributeListener。但是對(duì)于HttpSessionBindingListener,只有當(dāng)綁定或解綁的屬性值是監(jiān)聽(tīng)器的實(shí)例時(shí),servlet容器才會(huì)通知。舉例來(lái)說(shuō):

?
1
2
3
4
5
6
7
8
9
10
public class TestListener implements HttpSessionBindingListener{
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("HttpSessionBindingListener.valueBound");
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("HttpSessionBindingListener.valueUnbound");
}
}

我們自定義監(jiān)聽(tīng)器TestListener實(shí)現(xiàn)HttpSessionBindingListener,下面我們?cè)诖a中設(shè)置如下session屬性:

?
1
2
3
4
HttpSession session = request.getSession();
TestListener testListener=new TestListener();
session.setAttribute("listener", testListener);
session.removeAttribute("listener");

這里session的屬性值是我們的監(jiān)聽(tīng)器TestListener實(shí)例。所以這段代碼執(zhí)行時(shí),servlet容器會(huì)通知TestListener并回調(diào)valueBound和valueUnbound方法。

這里需要注意的是,當(dāng)調(diào)用session的invalidate方法或者session失效時(shí),也會(huì)回調(diào)valueUnbound方法。

3 servlet request相關(guān)監(jiān)聽(tīng)接口

詳解JavaWeb中的 Listener

3.1 ServletRequestEvent

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ServletRequestEvent extends java.util.EventObject {
private ServletRequest request;
public ServletRequestEvent(ServletContext sc, ServletRequest request) {
super(sc);
this.request = request;
}
public ServletRequest getServletRequest () {
return this.request;
}
public ServletContext getServletContext () {
return (ServletContext) super.getSource();
}
}

servlet請(qǐng)求的相關(guān)事件,當(dāng)request發(fā)生變化時(shí)會(huì)觸發(fā)該事件。事件源是ServletContext實(shí)例,并提供額外的獲取ServletContext和ServletRequest方法。

3.2 ServletRequestListener

?
1
2
3
4
public interface ServletRequestListener extends EventListener {
public void requestDestroyed ( ServletRequestEvent sre );
public void requestInitialized ( ServletRequestEvent sre );
}

當(dāng)請(qǐng)求初始化或者銷(xiāo)毀時(shí),即客戶(hù)端請(qǐng)求進(jìn)入web應(yīng)用(進(jìn)入servlet或者第一個(gè)filter)或web應(yīng)用返回響應(yīng)給客戶(hù)端(退出servlet或者第一個(gè)filter)。servlet容器構(gòu)造ServletRequestEvent實(shí)例,回調(diào)requestInitialized和requestDestroyed方法。

3.3 ServletRequestAttributeEvent

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ServletRequestAttributeEvent extends ServletRequestEvent {
private String name;
private Object value;
public ServletRequestAttributeEvent(ServletContext sc, ServletRequest request, String name, Object value) {
super(sc, request);
this.name = name;
this.value = value;
}
public String getName() {
return this.name;
}
public Object getValue() {
return this.value;
}
}

servlet請(qǐng)求屬性的相關(guān)事件,當(dāng)請(qǐng)求屬性發(fā)生變化時(shí)會(huì)觸發(fā)該事件。事件源是ServletContext實(shí)例,并提供額外的獲取屬性名和屬性值的方法。

3.4 ServletRequestAttributeListener

?
1
2
3
4
5
public interface ServletRequestAttributeListener extends EventListener {
public void attributeAdded(ServletRequestAttributeEvent srae);
public void attributeRemoved(ServletRequestAttributeEvent srae);
public void attributeReplaced(ServletRequestAttributeEvent srae);
}

當(dāng)請(qǐng)求的屬性發(fā)生增、刪、改的時(shí)候,servlet容器構(gòu)造ServletRequestAttributeEvent事件對(duì)象,分別回調(diào)attributeAdded、attributeRemoved、attributeReplaced方法。

這里需要注意的是attributeReplaced方法,當(dāng)屬性的值被替換的時(shí)候回調(diào)。這個(gè)時(shí)候如果調(diào)用ServletRequestAttributeEvent.getValue()方法返回的是替換之前的屬性值。

四、總結(jié)

至此,listener講完了。我們可以發(fā)現(xiàn)listener和servlet、filter有個(gè)共同點(diǎn),都是由容器進(jìn)行調(diào)度。我們只需要編寫(xiě)自己的listener去實(shí)現(xiàn)我們關(guān)心的監(jiān)聽(tīng)器接口并注冊(cè),剩下來(lái)的工作就是在我們自己的listener里面編寫(xiě)業(yè)務(wù)邏輯。

這邊博文介紹的listener是servlet3.0規(guī)范制定的。3.1已經(jīng)增加了一些事件監(jiān)聽(tīng)器接口,道理都是類(lèi)似的,讀者可以自行去了解。

原文鏈接:http://www.cnblogs.com/nantang/p/5899546.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 九九热在线视频观看这里只有精品 | 亚洲精品在看在线观看 | 国产精品久久久久毛片真精品 | 国产精亚洲视频 | 欧美一区二区三区在线观看免费 | 粉嫩高中生第一次不戴套 | 国产大片免费在线观看 | 午夜理论片日本中文在线 | 国产欧美日韩高清专区ho | chinaese中国女人厕所小便 | 亚洲欧美日韩精品久久亚洲区 | 放荡护士玩3p口述 | 四色6677最新永久网站 | 欧美亚洲第一区 | 福利视频一区二区思瑞 | 国产夜趣福利第一视频 | 成人天堂入口网站 | 性做久久久久久久 | 青青在线香蕉国产精品 | 女同志freelesvoices | 免费日本在线视频 | 9420高清完整版在线观看国语 | 国产成人精品一区二三区 | 99久久99热久久精品免 | 亚洲一级视频在线观看 | 久久精品热在线观看85 | 国产欧美成人免费观看 | 2021年国内自拍 | 天天狠天天透 | 亚洲图片一区二区三区 | 日本国产高清色www视频在线 | 亚洲午夜久久久久国产 | 亚洲精品www久久久久久久软件 | 欧美国产在线观看 | 天天色综合三 | 潘金莲西门庆一级淫片aaaaaa | 国产亚洲福利精品一区 | 国产精品网站在线观看 | 国产精品igao视频网网址 | 海绵宝宝第二季全集免费观看 | 无码AV毛片色欲欧洲美洲 |