? ? ?在上一章 查看tomcat啟動文件都干點啥---Catalina.java 中說道了構造Server,,這次嘗試著說一下Tomcat中Server的內容,首先看一下org.apache.catalina.Server接口中定義的方法:
從這里至少可以看出Server中包含很多Service,通過實現如下接口添加一個新的Service到Services的集合中,或者從集合中刪除指定的Service: ?
public void addService(Service service); public void removeService(Service service);
通過實現如下接口來完成通過service的名稱返回Service的操作:
public
Service findService(String name);
通過實現如下接口來完成獲取返回Server中所有Service的操作:
public
Service[] findServices();
對于Server的網絡內容的設置和獲取通過如下方法,包括設置地址,端口:
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);
獲取和設置父類的加載器:
public ClassLoader getParentClassLoader(); public void setParentClassLoader(ClassLoader parent);
如果設置了Catalina,那么也提供獲取和設置的方法:
public Catalina getCatalina(); public void setCatalina(Catalina catalina);
通過Server接口至少我們能夠得出結論:Server中包含多個Service對象。
結構如下:
值得注意的是Server借口繼承了Lifecycle接口,
public interface Server extends Lifecycle
Lifecycle 接口就是來控制Server極其組件的生命周期的,組件實現Lifecycle借口,就可以提供一致化的機制來啟動和停止組件。下面看一下?Lifecycle的內容:
首先是一些常量列表,小插曲,在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,實現了Service就是對外提供服務了,下面在看一下Service的接口定義:
看了定義的方法之后,很想逐一說明一下,可能會發現問題:
在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();
設置和獲取Container的方法:
public Container getContainer(); public void setContainer(Container container);
獲取和設置關聯的Server對象的方法:
public void setServer(Server server); public Server getServer();
給Service設置獲取名稱的方法:
public void setName(String name); public String getName();
以上就是Service接口定義的主要方法,得出在Service中包含一個或多個Connector,包含一個或多個Executors和一個Container對象。接著上面的Server---Service圖我們可以得出如下關系圖: ? ? ? ? ? ? ? ? ? ? ?
|---------Connector
Server----Service----|
?|----------Container
由此可知在Tomcat中的兩個重要的組件就是Connector和Container。下面我們著重看一下Connector和Container。
Container的主要功能是執行從客戶端接收的請求,然后給出回應。看一下Container接口定義的方法:
添加,刪除和獲取一個子Container:
public void addChild(Container child); public void removeChild(Container child); public Container findChild(String name); public Container[] findChildren();
對應的在Container中就應該有設置和獲取父Container的方法:
public void setParent(Container container); public Container getParent();
在Container中添加,移除和獲取事件監聽器:
public void addContainerListener(ContainerListener listener); public void removeContainerListener(ContainerListener listener); public ContainerListener[] findContainerListeners();
在Container中添加,移除和獲取屬性變更監聽器:
public void addPropertyChangeListener(PropertyChangeListener listener); public void removePropertyChangeListener(PropertyChangeListener listener);
觸發Container事件:
public void fireContainerEvent(String type, Object data);
記錄指向這個container的請求與響應的日志:
public
AccessLog getAccessLog();
設置和獲取作用在該container及其子container上的方法的延遲時間,單位秒:
public void setBackgroundProcessorDelay( int delay); public int getBackgroundProcessorDelay();
設置和獲取相關的集群:
public void setCluster(Cluster cluster); public Cluster getCluster();
設置和獲取Loadeer:
public void setLoader(Loader loader); public Loader getLoader();
設置和獲取負責管理該Container對應Session pool的Manager對象:
public void setManager(Manager manager); public Manager getManager();
設置和獲取Container的名字描述:
public void setName(String name); public String getName();
設置和獲取父類的ClassLoader:
public void setParentClassLoader(ClassLoader parent); public ClassLoader getParentClassLoader();
獲取Pipeline,負責管理該Container中的相關值:
public
Pipeline getPipeline();
設置和獲取Container的上下文資源:
public void setResources(DirContext resources); public DirContext getResources();
設置和獲取啟動和停止children container的線程數,可以并行的啟動和停止子container:
public void setStartStopThreads( int startStopThreads); public int getStartStopThreads();
Connector類中的變量已經方法實現如下:
代表一個Container的入口的變量:
protected Adapter adapter = null ;
實現Servlet的API規則匹配的變量:
protected Mapper mapper = new Mapper();
是否允許Trace:
protected boolean allowTrace = false ;
異步請求的超時時間:
protected long asyncTimeout = 10000;
是否允許DNS查找的標記:
protected boolean enableLookups = false ;
Mapper監聽器:
protected MapperListener mapperListener = new MapperListener(mapper, this );
GET和POST方法中,Container解析的最大的參數個數限制(默認值為1000,當設置數值小于0時,表示沒有限制):
protected int maxParameterCount = 10000;
Container接收POST方法傳遞的最大數據(默認值為2M):
protected int maxPostSize = 2 * 1024 * 1024;
在Container認證時候默認保存的最大數據:(默認值4K):
protected int maxSavePostSize = 4 * 1024;
一系列以逗號分割的,application/x-www-form-urlencoded形式的方法請求體,以什么方式轉化成方法的集合:
protected
String parseBodyMethods = "POST";
通過parseBodyMethods方式確定的方法集合:
protected
HashSet<String> parseBodyMethodsSet;
監聽請求端口的數量:(默認值為-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";
是否給每個接收到的請求設置安全連接標記:
protected boolean secure = false ;
一個String幫助對象:
protected static final StringManager sm = StringManager.getManager(Constants.Package);
關聯的Service對象:
protected Service service = null ;
URL編碼:
protected String URIEncoding = null ;
是否用body編碼給URL編碼:(不明白)
protected boolean useBodyEncodingForURI = false ;
是否用IP綁定虛擬主機:
protected boolean useIPVHosts = false ;
下面看一下Connector的構造函數:
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的構造函數中第一步是根據
protocol名稱HTTP/1.1,AJP/1.3或者protocol handler的類的全路徑名稱,下面是setProtocol方法的代碼實現:

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); } }
然后根據setProtocol方法設置的protocol handler進行實例化,在setProtocol方法中調用的setProtocolHandlerClassName方法,如下:
public void setProtocolHandlerClassName(String protocolHandlerClassName) { this .protocolHandlerClassName = protocolHandlerClassName; }
給connector的變量protocolHandlerClassName賦值,然后根據protocolHandlerClassName的值進行實例化。進而賦值給protocolHandler 變量。
然后是方法createObjectNameKeyProperties,該方法的作用是將請求的address參數拼接成字符串,包括type,port。下面是代碼實現:

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(); }
創建一個Request對象,Request是一個對Coyote Request的封裝,Coyote 這個東西很奇怪,是狼的意思,也不知道為什么外國人喜歡用動物名來給一個技術命名,hadoop,hive,pig等,說Coyote其實是對Socket的一個封裝,將Socket的請求和相應封裝成一個個Request和Response,具體如何封裝,都包涵什么信息等內容以后展開說明:

public Request createRequest() { Request request = new Request(); request.setConnector( this ); return (request); }
創建一個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對象,代碼實現如下:

@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(); }
設置和獲取是否允許Trace方法的執行:

public void setAllowTrace( boolean allowTrace) { this .allowTrace = allowTrace; setProperty( "allowTrace" , String.valueOf(allowTrace)); } public boolean getAllowTrace() { return ( this .allowTrace); }
設置和獲取異步請求的過期時間:

public void setAsyncTimeout( long asyncTimeout) { this .asyncTimeout= asyncTimeout; setProperty( "asyncTimeout" , String.valueOf(asyncTimeout)); } public long getAsyncTimeout() { return asyncTimeout; }
配置和獲取參數,參數這部分在前面的章節已經提到過了:

public void setAttribute(String name, Object value) { setProperty(name, String.valueOf(value)); } public Object getAttribute(String name) { return getProperty(name); }
剩下的方法都是設置和獲取前面定義的變量的值。
Server的主要接口已經介紹完了,下面看一下一些關鍵類的實現:
Server接口的標準實現是StandardServer類,同時StandServer也繼承了LifecycleMBeanBase類,看一下StandardServer中幾個重要方法的實現:
找幾個重要的方法說明一下:
向保存Connector的數組中添加新的Connector對象的方法addConnector,代碼實現如下:

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做關聯,connector.setService(this),然后將要添加的connector對象添加到保存Connector對象的數組中,此處使用數組,完全是處于效率的考慮。然后查看當前Server對象的狀態,如果狀態合法的話,那么啟動添加的connector對象。然后在更改此Connector的狀態。
返回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對象狀態合法,那么調用該connector的stop方法,然后將指定的connector對象關聯的Server置為null,剩下的內容就是整理移除connector對象的Connector集合。
設置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的關聯,然后要處理新的container對象。關聯Service,啟動Container。
由于Service中只有一個Container,所以沒有移除Container方法,在設置的時候其實是完成了刪除更新的操作。
看一下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對于個個組件生命周期的一致的生命周期的管理機制。
其實最開始想用本章說一下如何構建Server,但是覺得還是有必要將Server中的內容展開說明一下,在說如果構建的話可能更好理解。所以就有了這個只是具有說明意義的一節。?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
