Tomcat源碼分析(三)--連接器是如何與容器關(guān)聯(lián)的
系統(tǒng)
2019-08-12 01:32:19
2299 0
本系列轉(zhuǎn)載自?http://blog.csdn.net/haitao111313/article/category/1179996?
這篇文章要弄懂一個(gè)問(wèn)題,我們知道,一個(gè)鏈接器是跟一個(gè)容器關(guān)聯(lián)的,
容器跟鏈接器是在什么時(shí)候關(guān)聯(lián)上的?
在明白這個(gè)問(wèn)題前要先了解一下Digester庫(kù),這個(gè)庫(kù)簡(jiǎn)單的說(shuō)就是解析xml文件,這里有兩個(gè)概念:模式和規(guī)則,所謂模式就是一個(gè)xml的標(biāo)簽,規(guī)則就是遇到一個(gè)xml標(biāo)簽需要做什么,看一下他主要的三個(gè)方法:
? ? ? 1:addObjectCreate(String pattern, String className, String attributeName) ? ?根據(jù)模式pattern實(shí)例化一個(gè)對(duì)象className
? ? ? 2:addSetProperties(String pattern) ? 設(shè)置這個(gè)模式的屬性
? ? ? 3:addSetNext(String pattern, String methodName, String paramType) ?添加模式之間的關(guān)系,調(diào)用父模式的
? ? 上面可能不好理解,看tomcat是怎么用到Digester的,在org.apache.catalina.startup.Catalina.createStartDigester()的方法里(這個(gè)方法是在服務(wù)組件啟動(dòng)的時(shí)候調(diào)用的,詳細(xì)參考
Tomcat源碼分析(一)--服務(wù)啟動(dòng)
),在這個(gè)方法里有使用Digester來(lái)解析server.xml文件:
? ??
digester.addObjectCreate(
"Server/Service"
,??
????????????????????????????????
"org.apache.catalina.core.StandardService"
,??
????????????????????????????????
"className"
);
//?添加一個(gè)模式“Server/Service”,當(dāng)在xml文件(這里是server.xml)里遇到“Server”標(biāo)簽下的Service標(biāo)簽的時(shí)候,根據(jù)標(biāo)簽Service的屬性“className”為類名實(shí)例化一個(gè)對(duì)象,默認(rèn)類名是"org.apache.catalina.core.StandardServer"
??
???????digester.addSetProperties(
"Server/Service"
);?
//設(shè)置對(duì)象StandardService的屬性,有些什么屬性由xml里的Service標(biāo)簽指定
??
???????digester.addSetNext(
"Server/Service"
,??
???????????????????????????
"addService"
,??
???????????????????????????
"org.apache.catalina.Service"
);
//調(diào)用Service標(biāo)簽的上一級(jí)標(biāo)簽Server的對(duì)象(即StandardServer)的addService方法,把Service添加進(jìn)Server,設(shè)置它們的關(guān)系,最后一個(gè)參數(shù)表示addService方法的參數(shù)類型
??
這樣StandardServer和StandardService便有了所屬關(guān)系,現(xiàn)在看容器跟鏈接器是怎么連接的,再看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"
);??
這里很好理解,跟上面的是一樣的,遇到標(biāo)簽Server/Service/Connector的時(shí)候(這里簡(jiǎn)化了說(shuō)法,應(yīng)該是標(biāo)簽Server下的子標(biāo)簽Service的子標(biāo)簽Connector,有點(diǎn)拗口),實(shí)例化HttpConnector,然后在它的上一級(jí)父容器StandardService下調(diào)用addConnector,這樣就把鏈接器HttpConnector添加進(jìn)容器StandardService下了,看StandardService的addConnector方法:
public
?
void
?addConnector(Connector?connector)?{??
?????
synchronized
?(connectors)?{??
?????????connector.setContainer(
this
.container);?
//本來(lái)這里就應(yīng)該把容器和連接器關(guān)聯(lián)上的,但是在一開(kāi)始tomcat啟動(dòng)的時(shí)候,Digester是先添加鏈接器,所以容器container還是為null的,但是沒(méi)有關(guān)系,后面還會(huì)另一個(gè)地方關(guān)聯(lián)他們,這里應(yīng)該牢記的是容器和連接器都是在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);??
?????}??
??
?}??
這個(gè)方法很簡(jiǎn)單,就是把一個(gè)鏈接器connector添加到StandardService的connectors數(shù)組里,然后關(guān)聯(lián)上StandardService的容器。代碼上也做了一點(diǎn)說(shuō)明(很重要)。連接器添加進(jìn)StandardService了,現(xiàn)在看容器是什么時(shí)候添加進(jìn)StandardService的,其實(shí)方法是一樣的,再回到createStartDigester方法:
digester.addRuleSet(
new
?EngineRuleSet(
"Server/Service/"
));
//這句代碼是在createStartDigester方法里面
??
--------------------------》下面進(jìn)入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"
);?
//這里調(diào)用StandardService的方法setContainer方法,把容器添加進(jìn)StandardService里面
??
先不去糾結(jié)Digester是怎么進(jìn)入addRuleInstances方法的,當(dāng)我們調(diào)用了digester.addRuleSet(new EngineRuleSet("Server/Service/"));方法,Digester便會(huì)自動(dòng)調(diào)用到EngineRuleSet類的addRuleInstances方法,在方法里面無(wú)非也是添加各種模式和規(guī)則,根據(jù)上面的添加規(guī)則,很容易知道這里又添加了一個(gè)StandardEngine對(duì)象(容器),然后又在該模式的上一級(jí)模式Server/Service添加StandardEngine跟StandardService的關(guān)系,即通過(guò)setContainer方法把容器添加進(jìn)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)?{??
?????????????;??
?????????}??
?????}?????????????????????????????????????
//重點(diǎn)?。。。。。。?!
??
?????
synchronized
?(connectors)?{???????????
//下面是把StandardService下的所有連接器都關(guān)聯(lián)上StandardService下的容器,這樣連接器就跟容器關(guān)聯(lián)上了。
??
?????????
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);??
??
?}??
上面的代碼做了各種判斷,然后把容器設(shè)置到StandardService下,在“同步代碼塊”處,把容器和鏈接器關(guān)聯(lián)上了,至此,容器和鏈接器就關(guān)聯(lián)上了?;剡^(guò)頭想想,其實(shí)很簡(jiǎn)單,就是用Digester根據(jù)設(shè)定的模式讀取server.xml,然后調(diào)用了兩個(gè)關(guān)鍵的方法setContainer和addConnector,就把容器和鏈接器關(guān)聯(lián)上了。關(guān)聯(lián)上了就可以明白在
Tomcat源碼分析(二)--連接處理
一文的最后process方法里代碼:
connector.getContainer().invoke(request,?response);的含義了。下篇希望說(shuō)明白調(diào)用invoke之后發(fā)生的一切。
Tomcat源碼分析(三)--連接器是如何與容器關(guān)聯(lián)的?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】 元
喜歡作者