Jetty - Container源碼分析

1. 描述

Container提供管理bean的能力。

基于Jetty-9.4.8.v20171121。

1.1 API

public interface Container
{// 增加一個bean,如果bean是一個Container.Listener則隱含調用addEventListener(Container.Listener)方法// Container.Listener只關心兩個事件:(1)增加bean(2)刪除beanpublic boolean addBean(Object o);// 返回該Container里面所有的beanpublic Collection<Object> getBeans();// 返回指定類型(包括子類)的beanpublic <T> Collection<T> getBeans(Class<T> clazz);// 返回指定類型(包括子類)的第一個bean,如果不存在則返回nullpublic <T> T getBean(Class<T> clazz);// 刪除指定的bean,如果bean是一個Container.Listener,隱含調用removeEventListener(Container.Listener)public boolean removeBean(Object o);// 增加一個Listenerpublic void addEventListener(Listener listener);// 刪除一個Listenerpublic void removeEventListener(Listener listener);// 未托管一個bean(必須已經存在在Container里面),所以該bean不應該啟動,停止或銷毀void unmanage(Object bean);// 托管一個bean(必須已經存在在Container里面),所以該bean已啟動,已停止或銷毀void manage(Object bean);// 檢測該Container是否托管一個beanboolean isManaged(Object bean);// 增加一個bean,并且明確是否托管(即是否管理該bean的生命周期)// 如果已經增加返回true,如果已經存在返回false boolean addBean(Object o, boolean managed);// Container事件的監聽器// 如果一個增加的bean實現該接口將會收到該Container的事件public interface Listener{void beanAdded(Container parent,Object child);void beanRemoved(Container parent,Object child);}/*** Inherited Listener.* If an added bean implements this interface, then it will * be added to all contained beans that are themselves Containers
* 如果增加的bean實現該接口,則將該bean增加到當前Container里面所有bean類型為Container里面。*/public interface InheritedListener extends Listener{}/*** @param clazz the class of the beans* @return the list of beans of the given class from the entire managed hierarchy* @param <T> the Bean type*/public <T> Collection<T> getContainedBeans(Class<T> clazz); }  

從API可以看出Container主要維護bean并且監聽bean的增加和刪除事件。

?

1.2 類圖

從類圖可以看出,Container與LifeCycle接口很類似,都是很多組件的基本特征,其默認實現是ContainerLifeCycle。

2. ContainerLifeCycle

1.2類圖可以看出ContainerLifeCycle不僅是Container的默認實現,而且也是很多組件(Connector,Handler等)默認實現的父類。

2.1 類圖

?

ContainerLifeCycle自然要實現Container接口;?

ContainerLifeCycle繼承AbstractLifeCycle,而AbstractLifeCycle里面實現了LifeCycle的模板啟停方法start和stop;

繼承AbstractLifeCycle的子類只需要實現AbstractLifeCycle中增加的doStart和doStop實現子類具體的啟動和停止,具體請參考【Jetty - LifeCycle源碼分析】

ContainerLifeCycle.Bean:內部類,表示管理的Bean對象。

ContainerLifeCycle.Managed:內部類,被管理的Bean有幾種類型:POJO,MANAGED,UNMANAGED,AUTO。

2.2 doStart和doStop

??啟動主要分為如下兩個步驟:

?(1)設置標志位_doStart = true;

?(2)啟動具有生命周期的bean(a)如果托管bean并且未運行的,則啟動(b)如果是自動bean并且運行中,則設置為未托管;未運行的,則設置為托管,并且啟動;?

    // 以添加的順序啟動托管的bean@Overrideprotected void doStart() throws Exception{if (_destroyed)throw new IllegalStateException("Destroyed container cannot be restarted");// 標示已經啟動,addBean可以啟動其他的bean_doStarted = true;// 啟動托管和自動beansfor (Bean b : _beans) // 遍歷所有bean{if (b._bean instanceof LifeCycle){LifeCycle l = (LifeCycle)b._bean;switch(b._managed){case MANAGED: // 如果是托管bean,并且未運行,則啟動if (!l.isRunning())start(l);break;case AUTO: // 如果是自動beanif (l.isRunning()) // 如果已經運行了,則設置為未托管unmanage(b);else // 如果未運行,設置為托管,并且啟動{manage(b); start(l);}break;}}}// 此處調用父類的doStart方法,就是AbstractLifeCycle的doStart方法,其實是個空實現super.doStart();}  

停止主要分為兩個步驟:

(1)設置標志位;

(2)逆序停止具有生命周期的托管bean,為什么逆序?主要與啟動順序比較,防止bean之間有關聯出現錯誤,類似資源釋放。

    // 以添加的逆序停止具有生命周期的托管bean@Overrideprotected void doStop() throws Exception{  _doStarted = false; // 設置停止狀態位super.doStop(); // 調用AbstractLifeCycle的doStop方法,其實是個空方法List<Bean> reverse = new ArrayList<>(_beans);Collections.reverse(reverse); // 逆序for (Bean b : reverse) {   // 具有生命周期并且托管的beanif (b._managed==Managed.MANAGED && b._bean instanceof LifeCycle){LifeCycle l = (LifeCycle)b._bean;stop(l);}}}  

2.3 addBean

// o:bean,managed:bean類型
// 注意基本原則:在ContainerLifeCycle類里面有兩個字段_beans和_listener,如果添加的bean也是Container.Listener類型,則需要在_listener里面也增加一個
public boolean addBean(Object o, Managed managed){if (o==null || contains(o)) // 如果bean為null或者已經存在return false;Bean new_bean = new Bean(o); // 包裝為Bean對象// 如果bean是Container.Listenerif (o instanceof Container.Listener)addEventListener((Container.Listener)o);// 添加bean_beans.add(new_bean);// 通知所有_listeners,有新bean添加的事件for (Container.Listener l:_listeners)l.beanAdded(this,o);try{switch (managed){case UNMANAGED:unmanage(new_bean);break;case MANAGED:manage(new_bean);// 如果ContainerLifeCycle在啟動中,即調用doStart還沒有退出if (isStarting() && _doStarted) {  // 此處o是一個任意類型且是個public方法,此處直接轉為LifeCycle是否有問題?LifeCycle l = (LifeCycle)o;// 為什么有這樣的判斷?// doStart的過程(1)設置狀態位(2)以bean添加的順序啟動具有生命周期的bean,如果此時調用了addBean有可能同步的問題,導致新添加的bean沒有通過doStart啟動,所以需要在此處判斷如果未啟動,則啟動一下if (!l.isRunning()) start(l);}break;case AUTO:if (o instanceof LifeCycle){LifeCycle l = (LifeCycle)o;if (isStarting()) // 如果ContainerLifeCycle啟動中{if (l.isRunning()) // 如果bean運行中,則設置為未托管,不需要ContainerLifeCycle管理啟動unmanage(new_bean);else if (_doStarted) // 如果bean未運行,并且ContainerLifeCyle啟動中,則設置為托管bean并且啟動之{manage(new_bean);start(l);}elsenew_bean._managed=Managed.AUTO;      }else if (isStarted()) // 如果ContainerLifeCycle已經啟動unmanage(new_bean);else // ContainerLifeCycle未啟動new_bean._managed=Managed.AUTO;}elsenew_bean._managed=Managed.POJO;break;case POJO:new_bean._managed=Managed.POJO;}}catch (RuntimeException | Error e){throw e;}catch (Exception e){throw new RuntimeException(e);}if (LOG.isDebugEnabled())LOG.debug("{} added {}",this,new_bean);return true;}

?

// 刪除bean
private boolean remove(Bean bean){if (_beans.remove(bean)){boolean wasManaged = bean.isManaged(); // bean是否是托管類型unmanage(bean); // 設置bean為未托管類型for (Container.Listener l:_listeners) // 通知監聽器l.beanRemoved(this,bean._bean);// 如果被remove的bean是Listener,需要調用removeEventListenerif (bean._bean instanceof Container.Listener) removeEventListener((Container.Listener)bean._bean);// 如果是具有生命周期托管的bean需要停止。if (wasManaged && bean._bean instanceof LifeCycle){try{stop((LifeCycle)bean._bean);}catch(RuntimeException | Error e){throw e;}catch (Exception e){throw new RuntimeException(e);}}return true;}return false;}

?

2.4 插播Container管理bean的規則

通過前面的doStart和addBean可以基本確定Container管理bean的如下幾條規則:

ContainerLifeCycle是對容器化bean組件的一個生命周期的實現。

bean可以作為托管bean或未托管bean放入ContainerLifeCycle里面。

托管bean的啟動停止和銷毀由ContainerLifeCycle控制;未托管主要是為了dump,它們的生命周期必須獨立管理。

當一個沒有指定類型具有生命周期的bean加入到ContainerLifeCycle,ContianerLifeCycle可以推斷它的類型:

(1)如果增加的bean運行中,它將以未托管類型加入container;

(2)如果增加的bean未運行且container也未運行,它將以AUTO類型加入container;

(3)如果增加的bean未運行且container在啟動中,它將以托管類型加入container;

(4)如果增加的bean未運行且container已經啟動,它將以未托管類型加入container;

當container已經啟動,所有的托管bean也應該啟動。

任何AUTO類型的bean都將依據它們的狀態被分為托管或未托管,如果已經啟動則為未托管,否則將啟動它們然后設置為托管類型。

Contianer啟動之后添加的bean將不會被啟動,它們的狀態需要顯式管理。

當停止Container的時候,只有被這個Container啟動的bean才會停止。

如果一個bean被多個Container共享,那么該bean只能是未托管的,即在增加之前,應該被啟動

2.4.1 實例

?

2.5 manage和unmanage

?manage是設置bean為托管類型,unmanage設置bean為未托管類型。

可以理解為兩個相反的操作,需要注意如果被設置的bean是個Container,則需要將當前_listeners里面所有類型為InheritedListener的監聽器添加到該bean里面或從該bean里面移除。

// 托管bean
private void manage(Bean bean){if (bean._managed!=Managed.MANAGED){bean._managed=Managed.MANAGED; // 設置bean為托管if (bean._bean instanceof Container){for (Container.Listener l:_listeners){if (l instanceof InheritedListener) // 如果當前bean的listener里面有是InheritedListener需要增加到bean的_beans列表中{if (bean._bean instanceof ContainerLifeCycle)((ContainerLifeCycle)bean._bean).addBean(l,false);else((Container)bean._bean).addBean(l);}}}if (bean._bean instanceof AbstractLifeCycle){((AbstractLifeCycle)bean._bean).setStopTimeout(getStopTimeout());}}}

?

// 未托管bean    
private void unmanage(Bean bean){if (bean._managed!=Managed.UNMANAGED){if (bean._managed==Managed.MANAGED && bean._bean instanceof Container){for (Container.Listener l:_listeners){  // 如果監聽器是InheritedListener,需要將其從未托管的bean中移除if (l instanceof InheritedListener)((Container)bean._bean).removeBean(l);}}bean._managed=Managed.UNMANAGED;}}

  

2.6 addEventListener和removeEventListener

兩個是相反的操作,一個是增加Listener,另一個是刪除Listener。

如果待操作的Listener是InheritedListener子類,需要級聯操作。

@Overridepublic void addEventListener(Container.Listener listener){if (_listeners.contains(listener))return;_listeners.add(listener);// 新加的Listener需要被告知所有beanfor (Bean b:_beans){listener.beanAdded(this,b._bean);// 如果是InheritedListener需要增加到bean為Container的_beans列表中if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container){if (b._bean instanceof ContainerLifeCycle)((ContainerLifeCycle)b._bean).addBean(listener, false);else((Container)b._bean).addBean(listener);}}}

?

  @Overridepublic void removeEventListener(Container.Listener listener){if (_listeners.remove(listener)){// remove existing beansfor (Bean b:_beans){listener.beanRemoved(this,b._bean);// 與增加相反,需要級聯移除if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)((Container)b._bean).removeBean(listener);}}}  

2.7 updateBean  

最后ContainerLifeCycle還提供了重載的updateBean,入參一般是一個老bean和一個新bean。

一般操作都是先刪除老bean,然后增加新bean,都是復用上面提到的removeBean和addBean,不在詳細描述。?

轉載于:https://www.cnblogs.com/lujiango/p/8361415.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452849.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452849.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452849.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ubuntu中安裝FastDFS

1 安裝fastdfs依賴包 解壓縮libfastcommon-master.zip進入到libfastcommon-master的目錄中執行 ./make.sh執行 sudo ./make.sh install 2 安裝fastdfs 解壓縮fastdfs-master.zip進入到 fastdfs-master目錄中執行 ./make.sh執行 sudo ./make.sh install 3 配置跟蹤服務器tra…

python基本語句及其意思_Python語法基礎(1),一

一、Python的對象模型對象是Python語言中最基本的概率&#xff0c;在Python中處理的一切都是對象。Python中許多內置對象可提供編程者使用&#xff0c;內置對象可直接使用&#xff0c;如數字、字符串、列表 、del等&#xff1b;非內置對象需要導入模塊才能使用&#xff0c;如正…

什么是隧道技術

隧道技術是一種通過互聯網絡基礎設施在網絡之間傳遞數據的方式。使用隧道傳遞的數據可以是不同協議的數據幀或包&#xff0c;隧道協議將這些其它協議的數據幀或包重新封裝在新的包頭中發送&#xff0c;被封裝的數據包在隧道的兩個端點之間通過公共互聯網絡進行路由&#xff0c;…

詳解網絡數字電視的實現方法與關鍵技術

1、IPTV的實現方法 寬帶網絡數字電視&#xff0c;又稱IPTV或BTV&#xff0c;即交互式網絡電視&#xff0c;是一種利用寬帶互聯網、多媒體等多種技術于一體&#xff0c;向家庭用戶提供包括數字電視在內的多種交互式服務的嶄新技術。它能夠很好地適應當今網絡飛速發展的趨勢&…

有狀態的bean和無狀態的bean的區別

有狀態會話bean &#xff1a;每個用戶有自己特有的一個實例&#xff0c;在用戶的生存期內&#xff0c;bean保持了用戶的信息&#xff0c;即“有狀態”&#xff1b;一旦用戶滅亡&#xff08;調用結束或實例結束&#xff09;&#xff0c;bean的生命期也告結束。即每個用戶最初都會…

因為我想在博客園長呆,所以給博客園提一些改進建議

一晃眼我來博客園已經有4個月了&#xff0c;我的排名從9萬多上升到9千多&#xff0c;也有不少朋友關注了我&#xff0c;其實對我幫助更大的是博客園的管理團隊&#xff0c;他們對我的文章提出了很多很好的改進建議&#xff0c;從而讓我的文章水平有了很大的提升。 這里我從用戶…

double 二進制 java_C#中將double值變成二進制然后寫入文件,Java中載入該文件讀取此二進制double值時不正確...

目前已定位到是因為C#中的byte范圍是0到255&#xff0c;而java中byte值為-128到127導致的錯誤。嘗試過使用C#的sbyte來解決&#xff1a;bw1 new BinaryWriter(new FileStream("C:\\Users\\DELL\\Desktop\\SpatialIndex\\ctest1.bin", FileMode.Create));bw2 new Bi…

什么是移動IP

移動代理 &#xff08;Mobility Agent&#xff09;&#xff1a;又分為歸屬代理和外區代理兩類。歸屬代理是歸屬網上的移動代理&#xff0c;它至少有一個接口在歸屬網上。其責任是當移動節點移動到外區網時&#xff0c;截收發往該點的數據包&#xff0c;并使用隧道技術將這些數據…

Ubuntu中安裝nginxError

問題1&#xff1a;出現如下錯誤&#xff1a; ./configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCR…

項目經理如何把工作簡單化

做一件事有兩種方式。其一是把簡單的事情復雜化&#xff0c;另外就是把復雜的事情簡單化。項目經理應該如何選擇呢?恐怕大家會異口同聲的說&#xff0c;當然是把復雜的事情簡單化。但是&#xff0c;在實際工作中&#xff0c;很少有項目經理能夠做到這一點。他們會不知不覺中把…

[luogu P2590 ZJOI2008] 樹的統計 (樹鏈剖分)

題目描述 一棵樹上有n個節點&#xff0c;編號分別為1到n&#xff0c;每個節點都有一個權值w。 我們將以下面的形式來要求你對這棵樹完成一些操作&#xff1a; I. CHANGE u t : 把結點u的權值改為t II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值 III. QSUM u v: 詢問從…

jetty xml解析

1 configure configure為xml的根結點&#xff0c;class指定所配置的對象的類&#xff0c;這個configure會創建一個該類的對象&#xff0c;然后根據該xml對其進行配置。id用來對該對象進行標識&#xff0c;在整個jetty中具有唯一性&#xff0c;相同id的xml configure文件配置的是…

java 歌詞_請問吧內有大神用JAVA做過桌面歌詞嗎

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓寫了個簡單的例子給你&#xff1a;public class TextChangePane extends JComponent implements ActionListener {private static final int CYCLE_TIME 10000;private long startTime 0;private long nowTime 0;private float …

組播相對于單播和廣播的優勢

組播協議允許將一臺主機發送的數據通過網絡路由器和交換機復制到多個加入此組組播協議。 與現在廣泛使用的單播協議的不同之處在于&#xff0c;一個主機用單播協議向n個主機發送相同的數據時&#xff0c;發送主機需要分別向n個主機發送&#xff0c;共發送n次。一個主機用組播協…

安裝nginx及fastdfs-nginx-module

1.先了解背景&#xff1a; FastDFS為什么要結合Nginx以及FastDFS原理&#xff0c;請參考文章&#xff1a; FastDFS為什么要結合Nginx以及FastDFS原理 2.準備工作&#xff1a; 安裝安裝Nginx所需的環境&#xff0c;參考文獻&#xff1a;Ubuntu 18.04.1安裝Nginx apt install …

如何讓自己的內心強大起來

內心強大的人是指一個人的精神境界達到了一定的級別&#xff01;以至于讓人們折服&#xff01; 世界上有這么一種人&#xff0c;似乎特別得到老天爺的偏愛——他總是有自己的理想&#xff0c;并且總是努力去做&#xff0c;最重要的是&#xff0c;老天爺每一次都會幫他取得成功…

什么是軟件工程

軟件工程是指導計算機軟件開發和維護的一門工程學科。采用工程的概念、原理、技術和方法來開發與維護軟件&#xff0c;把經過時間考驗而證明正確的管理技術和當前能夠得到的最好的技術方法結合起來&#xff0c;以經濟地開發出高質量的軟件并有效地維護它&#xff0c;這就是軟件…

linux下的靜態庫與動態庫

目錄 靜態庫定義&#xff1a;生成及使用方法&#xff1a;靜態庫的優缺點動態庫定義&#xff1a;生成及使用方法&#xff1a;動態庫優缺點&#xff1a;靜態庫 先說說我們為什么需要庫&#xff1f; 當有些代碼我們大量會在程序中使用比如&#xff08;scanf&#xff0c;printf等&a…

esrgan_ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks【閱讀筆記】

針對SRGAN提出的幾點改進&#xff0c;獲得了PIRM2018視覺質量的第一名。首先是使用去掉BN層的Residual in Residual Dense Block作為網絡的basic unit。并且使用residual scling 和 smaller initialization幫助訓練更深的網絡。第二點改進是使用了Relativistic Discriminator來…

PostgreSQL Frontend/Backend protocol (通信協議)

標簽 PostgreSQL , protocol , proxy , 通信協議 背景 理解PostgreSQL的通信協議可以更好的開發類似SQL代理&#xff0c;SQL中間件&#xff0c;SQL防火墻&#xff0c;連接池等軟件。 學習資料與軟件 《PostgreSQL 讀寫分離代理 - Crunchy Proxy(base on golang)》 Postgres on …