? ? ?在上一章 查看tomcat啟動文件都干點(diǎn)啥---Catalina.java 中說道了構(gòu)造Server,,這次嘗試著說一下Tomcat中Server的內(nèi)容,首先看一下org.apache.catalina.Server接口中定義的方法:
從這里至少可以看出Server中包含很多Service,通過實(shí)現(xiàn)如下接口添加一個新的Service到Services的集合中,或者從集合中刪除指定的Service: ?
public
void
addService(Service service);
public
void
removeService(Service service);
通過實(shí)現(xiàn)如下接口來完成通過service的名稱返回Service的操作:
public
Service findService(String name);
通過實(shí)現(xiàn)如下接口來完成獲取返回Server中所有Service的操作:
public
Service[] findServices();
對于Server的網(wǎng)絡(luò)內(nèi)容的設(shè)置和獲取通過如下方法,包括設(shè)置地址,端口:
public
int
getPort();
public
void
setPort(
int
port);
public
String getAddress();
public
void
setAddress(String address);
獲取和指定shotdown命令:
public
String getShutdown();
public
void
setShutdown(String shutdown);
獲取和設(shè)置父類的加載器:
public
ClassLoader getParentClassLoader();
public
void
setParentClassLoader(ClassLoader parent);
如果設(shè)置了Catalina,那么也提供獲取和設(shè)置的方法:
public
Catalina getCatalina();
public
void
setCatalina(Catalina catalina);
通過Server接口至少我們能夠得出結(jié)論:Server中包含多個Service對象。
結(jié)構(gòu)如下:
值得注意的是Server借口繼承了Lifecycle接口,
public
interface
Server
extends
Lifecycle
Lifecycle 接口就是來控制Server極其組件的生命周期的,組件實(shí)現(xiàn)Lifecycle借口,就可以提供一致化的機(jī)制來啟動和停止組件。下面看一下?Lifecycle的內(nèi)容:
首先是一些常量列表,小插曲,在Tomcat7.0.53中,tomcat在此處的注釋有小問題,有興趣的人可以看一下。
//
組件初始化之前的事件
public
static
final
String BEFORE_INIT_EVENT = "before_init"
;
//
組件初始化之后的事件
public
static
final
String AFTER_INIT_EVENT = "after_init"
;
//
組件start的事件
public
static
final
String START_EVENT = "start"
;
//
組件start之前的事件
public
static
final
String BEFORE_START_EVENT = "before_start"
;
//
組件start之后的事件
public
static
final
String AFTER_START_EVENT = "after_start"
;
//
組件stop之后的事件
public
static
final
String STOP_EVENT = "stop"
;
//
組件stop之前的事件
public
static
final
String BEFORE_STOP_EVENT = "before_stop"
;
//
組件stop之后的事件
public
static
final
String AFTER_STOP_EVENT = "after_stop"
;
//
組件destrop之后的事件
public
static
final
String AFTER_DESTROY_EVENT = "after_destroy"
;
//
組件destrop之前的事件
public
static
final
String BEFORE_DESTROY_EVENT = "before_destroy"
;
//
組件periodic的事件
public
static
final
String PERIODIC_EVENT = "periodic";
下面就是Lifecycle接口定義的方法列表:
既然Server中包含的主要對象就是Service,實(shí)現(xiàn)了Service就是對外提供服務(wù)了,下面在看一下Service的接口定義:
看了定義的方法之后,很想逐一說明一下,可能會發(fā)現(xiàn)問題:
在Service中添加或移除connector的方法:
public
void
addConnector(Connector connector);
public
void
removeConnector(Connector connector);
? ? 說明在每個Service中有多個Connector。
在Service中添加或移除Executor的方法:
public
void
addExecutor(Executor ex);
public
void
removeExecutor(Executor ex);
返回所有Connector的方法:
public
Connector[] findConnectors();
返回所有executor的方法:
public
Executor[] findExecutors();
設(shè)置和獲取Container的方法:
public
Container getContainer();
public
void
setContainer(Container container);
獲取和設(shè)置關(guān)聯(lián)的Server對象的方法:
public
void
setServer(Server server);
public
Server getServer();
給Service設(shè)置獲取名稱的方法:
public
void
setName(String name);
public
String getName();
以上就是Service接口定義的主要方法,得出在Service中包含一個或多個Connector,包含一個或多個Executors和一個Container對象。接著上面的Server---Service圖我們可以得出如下關(guān)系圖: ? ? ? ? ? ? ? ? ? ? ?
|---------Connector
Server----Service----|
?|----------Container
由此可知在Tomcat中的兩個重要的組件就是Connector和Container。下面我們著重看一下Connector和Container。
Container的主要功能是執(zhí)行從客戶端接收的請求,然后給出回應(yīng)。看一下Container接口定義的方法:
添加,刪除和獲取一個子Container:
public
void
addChild(Container child);
public
void
removeChild(Container child);
public
Container findChild(String name);
public
Container[] findChildren();
對應(yīng)的在Container中就應(yīng)該有設(shè)置和獲取父Container的方法:
public
void
setParent(Container container);
public
Container getParent();
在Container中添加,移除和獲取事件監(jiān)聽器:
public
void
addContainerListener(ContainerListener listener);
public
void
removeContainerListener(ContainerListener listener);
public
ContainerListener[] findContainerListeners();
在Container中添加,移除和獲取屬性變更監(jiān)聽器:
public
void
addPropertyChangeListener(PropertyChangeListener listener);
public
void
removePropertyChangeListener(PropertyChangeListener listener);
觸發(fā)Container事件:
public
void
fireContainerEvent(String type, Object data);
記錄指向這個container的請求與響應(yīng)的日志:
public
AccessLog getAccessLog();
設(shè)置和獲取作用在該container及其子container上的方法的延遲時間,單位秒:
public
void
setBackgroundProcessorDelay(
int
delay);
public
int
getBackgroundProcessorDelay();
設(shè)置和獲取相關(guān)的集群:
public
void
setCluster(Cluster cluster);
public
Cluster getCluster();
設(shè)置和獲取Loadeer:
public
void
setLoader(Loader loader);
public
Loader getLoader();
設(shè)置和獲取負(fù)責(zé)管理該Container對應(yīng)Session pool的Manager對象:
public
void
setManager(Manager manager);
public
Manager getManager();
設(shè)置和獲取Container的名字描述:
public
void
setName(String name);
public
String getName();
設(shè)置和獲取父類的ClassLoader:
public
void
setParentClassLoader(ClassLoader parent);
public
ClassLoader getParentClassLoader();
獲取Pipeline,負(fù)責(zé)管理該Container中的相關(guān)值:
public
Pipeline getPipeline();
設(shè)置和獲取Container的上下文資源:
public
void
setResources(DirContext resources);
public
DirContext getResources();
設(shè)置和獲取啟動和停止children container的線程數(shù),可以并行的啟動和停止子container:
public
void
setStartStopThreads(
int
startStopThreads);
public
int
getStartStopThreads();
Connector類中的變量已經(jīng)方法實(shí)現(xiàn)如下:
代表一個Container的入口的變量:
protected
Adapter adapter =
null
;
實(shí)現(xiàn)Servlet的API規(guī)則匹配的變量:
protected
Mapper mapper =
new
Mapper();
是否允許Trace:
protected
boolean
allowTrace =
false
;
異步請求的超時時間:
protected
long
asyncTimeout = 10000;
是否允許DNS查找的標(biāo)記:
protected
boolean
enableLookups =
false
;
Mapper監(jiān)聽器:
protected
MapperListener mapperListener =
new
MapperListener(mapper,
this
);
GET和POST方法中,Container解析的最大的參數(shù)個數(shù)限制(默認(rèn)值為1000,當(dāng)設(shè)置數(shù)值小于0時,表示沒有限制):
protected
int
maxParameterCount = 10000;
Container接收POST方法傳遞的最大數(shù)據(jù)(默認(rèn)值為2M):
protected
int
maxPostSize = 2 * 1024 * 1024;
在Container認(rèn)證時候默認(rèn)保存的最大數(shù)據(jù):(默認(rèn)值4K):
protected
int
maxSavePostSize = 4 * 1024;
一系列以逗號分割的,application/x-www-form-urlencoded形式的方法請求體,以什么方式轉(zhuǎn)化成方法的集合:
protected
String parseBodyMethods = "POST";
通過parseBodyMethods方式確定的方法集合:
protected
HashSet<String> parseBodyMethodsSet;
監(jiān)聽請求端口的數(shù)量:(默認(rèn)值為-1):
protected
int
port = -1;
connector對象將請求重定向到那個Server:
protected
String proxyName =
null
;
connector對象請求重定向到server的哪個端口:
protected
int
proxyPort = 0;
? 從no-ssl到ssl重定向端口:
protected
int
redirectPort = 443;
通過connector接收到的所有請求的請求方案:
protected
String scheme = "http";
是否給每個接收到的請求設(shè)置安全連接標(biāo)記:
protected
boolean
secure =
false
;
一個String幫助對象:
protected
static
final
StringManager sm =
StringManager.getManager(Constants.Package);
關(guān)聯(lián)的Service對象:
protected
Service service =
null
;
URL編碼:
protected
String URIEncoding =
null
;
是否用body編碼給URL編碼:(不明白)
protected
boolean
useBodyEncodingForURI =
false
;
是否用IP綁定虛擬主機(jī):
protected
boolean
useIPVHosts =
false
;
下面看一下Connector的構(gòu)造函數(shù):
public
Connector() {
this
(
null
);
}
public
Connector(String protocol) {
setProtocol(protocol);
//
Instantiate protocol handler
try
{
Class
<?> clazz =
Class.forName(protocolHandlerClassName);
this
.protocolHandler =
(ProtocolHandler) clazz.newInstance();
}
catch
(Exception e) {
log.error(sm.getString(
"coyoteConnector.protocolHandlerInstantiationFailed"
), e);
}
}
Connector的構(gòu)造函數(shù)中第一步是根據(jù)
protocol名稱HTTP/1.1,AJP/1.3或者protocol handler的類的全路徑名稱,下面是setProtocol方法的代碼實(shí)現(xiàn):
public
void
setProtocol(String protocol) {
if
(AprLifecycleListener.isAprAvailable()) {
if
("HTTP/1.1"
.equals(protocol)) {
setProtocolHandlerClassName
(
"org.apache.coyote.http11.Http11AprProtocol"
);
}
else
if
("AJP/1.3"
.equals(protocol)) {
setProtocolHandlerClassName
(
"org.apache.coyote.ajp.AjpAprProtocol"
);
}
else
if
(protocol !=
null
) {
setProtocolHandlerClassName(protocol);
}
else
{
setProtocolHandlerClassName
(
"org.apache.coyote.http11.Http11AprProtocol"
);
}
}
else
{
if
("HTTP/1.1"
.equals(protocol)) {
setProtocolHandlerClassName
(
"org.apache.coyote.http11.Http11Protocol"
);
}
else
if
("AJP/1.3"
.equals(protocol)) {
setProtocolHandlerClassName
(
"org.apache.coyote.ajp.AjpProtocol"
);
}
else
if
(protocol !=
null
) {
setProtocolHandlerClassName(protocol);
}
}
然后根據(jù)setProtocol方法設(shè)置的protocol handler進(jìn)行實(shí)例化,在setProtocol方法中調(diào)用的setProtocolHandlerClassName方法,如下:
public
void
setProtocolHandlerClassName(String protocolHandlerClassName) {
this
.protocolHandlerClassName =
protocolHandlerClassName;
}
給connector的變量protocolHandlerClassName賦值,然后根據(jù)protocolHandlerClassName的值進(jìn)行實(shí)例化。進(jìn)而賦值給protocolHandler 變量。
然后是方法createObjectNameKeyProperties,該方法的作用是將請求的address參數(shù)拼接成字符串,包括type,port。下面是代碼實(shí)現(xiàn):
protected
String createObjectNameKeyProperties(String type) {
Object addressObj
= getProperty("address"
);
StringBuilder sb
=
new
StringBuilder("type="
);
sb.append(type);
sb.append(
",port="
);
int
port =
getPort();
if
(port > 0
) {
sb.append(getPort());
}
else
{
sb.append(
"auto-"
);
sb.append(getProperty(
"nameIndex"
));
}
String address
= ""
;
if
(addressObj
instanceof
InetAddress) {
address
=
((InetAddress) addressObj).getHostAddress();
}
else
if
(addressObj !=
null
) {
address
=
addressObj.toString();
}
if
(address.length() > 0
) {
sb.append(
",address="
);
sb.append(ObjectName.quote(address));
}
return
sb.toString();
}
創(chuàng)建一個Request對象,Request是一個對Coyote Request的封裝,Coyote 這個東西很奇怪,是狼的意思,也不知道為什么外國人喜歡用動物名來給一個技術(shù)命名,hadoop,hive,pig等,說Coyote其實(shí)是對Socket的一個封裝,將Socket的請求和相應(yīng)封裝成一個個Request和Response,具體如何封裝,都包涵什么信息等內(nèi)容以后展開說明:
public
Request createRequest() {
Request request
=
new
Request();
request.setConnector(
this
);
return
(request);
}
創(chuàng)建一個Response對象:
public
Response createResponse() {
Response response
=
new
Response();
response.setConnector(
this
);
return
(response);
}
這里面值得注意的地方就是在request和response中,都有setConnector方法,所有connector是request和response的一個屬性。
下面看方法destroyInternal,這個方法是在LifecycleMBeanBase類中定義的,用來銷毀mapperListener,protocolHandler從Service中移除這個Connector對象,代碼實(shí)現(xiàn)如下:
@Override
protected
void
destroyInternal()
throws
LifecycleException {
mapperListener.destroy();
try
{
protocolHandler.destroy();
}
catch
(Exception e) {
throw
new
LifecycleException
(sm.getString
(
"coyoteConnector.protocolHandlerDestroyFailed"
), e);
}
if
(getService() !=
null
) {
getService().removeConnector(
this
);
}
super
.destroyInternal();
}
設(shè)置和獲取是否允許Trace方法的執(zhí)行:
public
void
setAllowTrace(
boolean
allowTrace) {
this
.allowTrace =
allowTrace;
setProperty(
"allowTrace"
, String.valueOf(allowTrace));
}
public
boolean
getAllowTrace() {
return
(
this
.allowTrace);
}
設(shè)置和獲取異步請求的過期時間:
public
void
setAsyncTimeout(
long
asyncTimeout) {
this
.asyncTimeout=
asyncTimeout;
setProperty(
"asyncTimeout"
, String.valueOf(asyncTimeout));
}
public
long
getAsyncTimeout() {
return
asyncTimeout;
}
配置和獲取參數(shù),參數(shù)這部分在前面的章節(jié)已經(jīng)提到過了:
public
void
setAttribute(String name, Object value) {
setProperty(name, String.valueOf(value));
}
public
Object getAttribute(String name) {
return
getProperty(name);
}
剩下的方法都是設(shè)置和獲取前面定義的變量的值。
Server的主要接口已經(jīng)介紹完了,下面看一下一些關(guān)鍵類的實(shí)現(xiàn):
Server接口的標(biāo)準(zhǔn)實(shí)現(xiàn)是StandardServer類,同時StandServer也繼承了LifecycleMBeanBase類,看一下StandardServer中幾個重要方法的實(shí)現(xiàn):
找?guī)讉€重要的方法說明一下:
向保存Connector的數(shù)組中添加新的Connector對象的方法addConnector,代碼實(shí)現(xiàn)如下:
public
void
addConnector(Connector connector) {
synchronized
(connectors) {
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
(getState().isAvailable()) {
try
{
connector.start();
}
catch
(LifecycleException e) {
log.error(sm.getString(
"standardService.connector.startFailed"
,
connector), e);
}
}
//
Report this property change to interested listeners
support.firePropertyChange("connector",
null
, connector);
}
}
首先要把Connector和Serice做關(guān)聯(lián),connector.setService(this),然后將要添加的connector對象添加到保存Connector對象的數(shù)組中,此處使用數(shù)組,完全是處于效率的考慮。然后查看當(dāng)前Server對象的狀態(tài),如果狀態(tài)合法的話,那么啟動添加的connector對象。然后在更改此Connector的狀態(tài)。
返回Connector集合:
@Override
public
Connector[] findConnectors() {
return
(connectors);
}
在Connector集合中移除connector:
public
void
removeConnector(Connector connector) {
synchronized
(connectors) {
int
j = -1
;
for
(
int
i = 0; i < connectors.length; i++
) {
if
(connector ==
connectors[i]) {
j
=
i;
break
;
}
}
if
(j < 0
)
return
;
if
(connectors[j].getState().isAvailable()) {
try
{
connectors[j].stop();
}
catch
(LifecycleException e) {
log.error(sm.getString(
"standardService.connector.stopFailed"
,
connectors[j]), e);
}
}
connector.setService(
null
);
int
k = 0
;
Connector results[]
=
new
Connector[connectors.length - 1
];
for
(
int
i = 0; i < connectors.length; i++
) {
if
(i !=
j)
results[k
++] =
connectors[i];
}
connectors
=
results;
//
Report this property change to interested listeners
support.firePropertyChange("connector", connector,
null
);
}
}
首先遍歷Connector集合,找到要移除的connector,如果指定的connector對象狀態(tài)合法,那么調(diào)用該connector的stop方法,然后將指定的connector對象關(guān)聯(lián)的Server置為null,剩下的內(nèi)容就是整理移除connector對象的Connector集合。
設(shè)置Container方法,該container對象處理Service中所有connector中的請求:
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
(getState().isAvailable() && (
this
.container !=
null
)) {
try
{
this
.container.start();
}
catch
(LifecycleException e) {
//
Ignore
}
}
if
(getState().isAvailable() && (oldContainer !=
null
)) {
try
{
oldContainer.stop();
}
catch
(LifecycleException e) {
//
Ignore
}
}
//
Report this property change to interested listeners
support.firePropertyChange("container", oldContainer,
this
.container);
}
首先是處理這個Server中原有的Container,原來可能有Container也有可能沒有,所以要做判斷,如果存在的話,解除和Service的關(guān)聯(lián),然后要處理新的container對象。關(guān)聯(lián)Service,啟動Container。
由于Service中只有一個Container,所以沒有移除Container方法,在設(shè)置的時候其實(shí)是完成了刪除更新的操作。
看一下startInternal方法:
protected
void
startInternal()
throws
LifecycleException {
if
(log.isInfoEnabled())
log.info(sm.getString(
"standardService.start.name",
this
.name));
setState(LifecycleState.STARTING);
//
Start our defined Container first
if
(container !=
null
) {
synchronized
(container) {
container.start();
}
}
synchronized
(executors) {
for
(Executor executor: executors) {
executor.start();
}
}
//
Start our defined Connectors second
synchronized
(connectors) {
for
(Connector connector: connectors) {
try
{
//
If it has already failed, don't try and start it
if
(connector.getState() !=
LifecycleState.FAILED) {
connector.start();
}
}
catch
(Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed"
,
connector), e);
}
}
}
}
該方法就是逐一啟動Service中的組件,Container,Executor,Connector。
stopInternal方法:
protected
void
stopInternal()
throws
LifecycleException {
//
Pause connectors first
synchronized
(connectors) {
for
(Connector connector: connectors) {
try
{
connector.pause();
}
catch
(Exception e) {
log.error(sm.getString(
"standardService.connector.pauseFailed"
,
connector), e);
}
}
}
if
(log.isInfoEnabled())
log.info(sm.getString(
"standardService.stop.name",
this
.name));
setState(LifecycleState.STOPPING);
//
Stop our defined Container second
if
(container !=
null
) {
synchronized
(container) {
container.stop();
}
}
//
Now stop the connectors
synchronized
(connectors) {
for
(Connector connector: connectors) {
if
(!
LifecycleState.STARTED.equals(
connector.getState())) {
//
Connectors only need stopping if they are currently
//
started. They may have failed to start or may have been
//
stopped (e.g. via a JMX call)
continue
;
}
try
{
connector.stop();
}
catch
(Exception e) {
log.error(sm.getString(
"standardService.connector.stopFailed"
,
connector), e);
}
}
}
synchronized
(executors) {
for
(Executor executor: executors) {
executor.stop();
}
}
}
由這兩個方法也能看出來Lifecycle對于個個組件生命周期的一致的生命周期的管理機(jī)制。
其實(shí)最開始想用本章說一下如何構(gòu)建Server,但是覺得還是有必要將Server中的內(nèi)容展開說明一下,在說如果構(gòu)建的話可能更好理解。所以就有了這個只是具有說明意義的一節(jié)。?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

