Tomcat源碼分析(三)--連接器是如何與容器關聯的
系統
2019-08-12 01:32:19
1917 0
本系列轉載自?http://blog.csdn.net/haitao111313/article/category/1179996?
這篇文章要弄懂一個問題,我們知道,一個鏈接器是跟一個容器關聯的,
容器跟鏈接器是在什么時候關聯上的?
在明白這個問題前要先了解一下Digester庫,這個庫簡單的說就是解析xml文件,這里有兩個概念:模式和規則,所謂模式就是一個xml的標簽,規則就是遇到一個xml標簽需要做什么,看一下他主要的三個方法:
? ? ? 1:addObjectCreate(String pattern, String className, String attributeName) ? ?根據模式pattern實例化一個對象className
? ? ? 2:addSetProperties(String pattern) ? 設置這個模式的屬性
? ? ? 3:addSetNext(String pattern, String methodName, String paramType) ?添加模式之間的關系,調用父模式的
? ? 上面可能不好理解,看tomcat是怎么用到Digester的,在org.apache.catalina.startup.Catalina.createStartDigester()的方法里(這個方法是在服務組件啟動的時候調用的,詳細參考
Tomcat源碼分析(一)--服務啟動
),在這個方法里有使用Digester來解析server.xml文件:
? ??
digester.addObjectCreate(
"Server/Service"
,??
????????????????????????????????
"org.apache.catalina.core.StandardService"
,??
????????????????????????????????
"className"
);
//?添加一個模式“Server/Service”,當在xml文件(這里是server.xml)里遇到“Server”標簽下的Service標簽的時候,根據標簽Service的屬性“className”為類名實例化一個對象,默認類名是"org.apache.catalina.core.StandardServer"
??
???????digester.addSetProperties(
"Server/Service"
);?
//設置對象StandardService的屬性,有些什么屬性由xml里的Service標簽指定
??
???????digester.addSetNext(
"Server/Service"
,??
???????????????????????????
"addService"
,??
???????????????????????????
"org.apache.catalina.Service"
);
//調用Service標簽的上一級標簽Server的對象(即StandardServer)的addService方法,把Service添加進Server,設置它們的關系,最后一個參數表示addService方法的參數類型
??
這樣StandardServer和StandardService便有了所屬關系,現在看容器跟鏈接器是怎么連接的,再看createStartDigester方法:
digester.addObjectCreate(
"Server/Service/Connector"
,??
?????????????????????????????????
"org.apache.catalina.connector.http.HttpConnector"
,??
?????????????????????????????????
"className"
);??
????????digester.addSetProperties(
"Server/Service/Connector"
);??
????????digester.addSetNext(
"Server/Service/Connector"
,??
????????????????????????????
"addConnector"
,??
????????????????????????????
"org.apache.catalina.Connector"
);??
這里很好理解,跟上面的是一樣的,遇到標簽Server/Service/Connector的時候(這里簡化了說法,應該是標簽Server下的子標簽Service的子標簽Connector,有點拗口),實例化HttpConnector,然后在它的上一級父容器StandardService下調用addConnector,這樣就把鏈接器HttpConnector添加進容器StandardService下了,看StandardService的addConnector方法:
public
?
void
?addConnector(Connector?connector)?{??
?????
synchronized
?(connectors)?{??
?????????connector.setContainer(
this
.container);?
//本來這里就應該把容器和連接器關聯上的,但是在一開始tomcat啟動的時候,Digester是先添加鏈接器,所以容器container還是為null的,但是沒有關系,后面還會另一個地方關聯他們,這里應該牢記的是容器和連接器都是在Service里面
??
?????????connector.setService(
this
);??
?????????Connector?results[]?=?
new
?Connector[connectors.length?+?
1
];??
?????????System.arraycopy(connectors,?
0
,?results,?
0
,?connectors.length);??
?????????results[connectors.length]?=?connector;??
?????????connectors?=?results;??
??
?????????
if
?(initialized)?{??
?????????????
try
?{??
?????????????????connector.initialize();??
?????????????}?
catch
?(LifecycleException?e)?{??
?????????????????e.printStackTrace(System.err);??
?????????????}??
?????????}??
??
?????????
if
?(started?&&?(connector?
instanceof
?Lifecycle))?{??
?????????????
try
?{??
?????????????????((Lifecycle)?connector).start();??
?????????????}?
catch
?(LifecycleException?e)?{??
?????????????????;??
?????????????}??
?????????}??
??
?????????
//?Report?this?property?change?to?interested?listeners
??
?????????support.firePropertyChange(
"connector"
,?
null
,?connector);??
?????}??
??
?}??
這個方法很簡單,就是把一個鏈接器connector添加到StandardService的connectors數組里,然后關聯上StandardService的容器。代碼上也做了一點說明(很重要)。連接器添加進StandardService了,現在看容器是什么時候添加進StandardService的,其實方法是一樣的,再回到createStartDigester方法:
digester.addRuleSet(
new
?EngineRuleSet(
"Server/Service/"
));
//這句代碼是在createStartDigester方法里面
??
--------------------------》下面進入EngineRuleSet類的addRuleInstances方法??
public
?
void
?addRuleInstances(Digester?digester)?{??
???????digester.addObjectCreate(prefix?+?
"Engine"
,??
????????????????????????????????
"org.apache.catalina.core.StandardEngine"
,??
????????????????????????????????
"className"
);??
???????digester.addSetProperties(prefix?+?
"Engine"
);??
???????digester.addRule(prefix?+?
"Engine"
,??
????????????????????????
new
?LifecycleListenerRule??
????????????????????????(digester,??
?????????????????????????
"org.apache.catalina.startup.EngineConfig"
,??
?????????????????????????
"engineConfigClass"
));??
???????digester.addSetNext(prefix?+?
"Engine"
,??
???????????????????????????
"setContainer"
,??
???????????????????????????
"org.apache.catalina.Container"
);?
//這里調用StandardService的方法setContainer方法,把容器添加進StandardService里面
??
先不去糾結Digester是怎么進入addRuleInstances方法的,當我們調用了digester.addRuleSet(new EngineRuleSet("Server/Service/"));方法,Digester便會自動調用到EngineRuleSet類的addRuleInstances方法,在方法里面無非也是添加各種模式和規則,根據上面的添加規則,很容易知道這里又添加了一個StandardEngine對象(容器),然后又在該模式的上一級模式Server/Service添加StandardEngine跟StandardService的關系,即通過setContainer方法把容器添加進StandardService里。以下是StandardService的setContainer方法:
public
?
void
?setContainer(Container?container)?{??
?????Container?oldContainer?=?
this
.container;??
?????
if
?((oldContainer?!=?
null
)?&&?(oldContainer?
instanceof
?Engine))??
?????????((Engine)?oldContainer).setService(
null
);??
?????
this
.container?=?container;??
?????
if
?((
this
.container?!=?
null
)?&&?(
this
.container?
instanceof
?Engine))??
?????????((Engine)?
this
.container).setService(
this
);??
?????
if
?(started?&&?(
this
.container?!=?
null
)?&&??
?????????(
this
.container?
instanceof
?Lifecycle))?{??
?????????
try
?{??
?????????????((Lifecycle)?
this
.container).start();??
?????????}?
catch
?(LifecycleException?e)?{??
?????????????;??
?????????}??
?????}?????????????????????????????????????
//重點!!!!!!!!
??
?????
synchronized
?(connectors)?{???????????
//下面是把StandardService下的所有連接器都關聯上StandardService下的容器,這樣連接器就跟容器關聯上了。
??
?????????
for
?(
int
?i?=?
0
;?i?<?connectors.length;?i++)??
?????????????connectors[i].setContainer(
this
.container);??
?????}??
?????
if
?(started?&&?(oldContainer?!=?
null
)?&&??
?????????(oldContainer?
instanceof
?Lifecycle))?{??
?????????
try
?{??
?????????????((Lifecycle)?oldContainer).stop();??
?????????}?
catch
?(LifecycleException?e)?{??
?????????????;??
?????????}??
?????}??
??
?????
//?Report?this?property?change?to?interested?listeners
??
?????support.firePropertyChange(
"container"
,?oldContainer,?
this
.container);??
??
?}??
上面的代碼做了各種判斷,然后把容器設置到StandardService下,在“同步代碼塊”處,把容器和鏈接器關聯上了,至此,容器和鏈接器就關聯上了。回過頭想想,其實很簡單,就是用Digester根據設定的模式讀取server.xml,然后調用了兩個關鍵的方法setContainer和addConnector,就把容器和鏈接器關聯上了。關聯上了就可以明白在
Tomcat源碼分析(二)--連接處理
一文的最后process方法里代碼:
connector.getContainer().invoke(request,?response);的含義了。下篇希望說明白調用invoke之后發生的一切。
Tomcat源碼分析(三)--連接器是如何與容器關聯的?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】 元
喜歡作者