Connector概述
Connector是Jetty中可以直接接受客戶端連接的抽象,一個(gè)Connector監(jiān)聽(tīng)Jetty服務(wù)器的一個(gè)端口,所有客戶端的連接請(qǐng)求首先通過(guò)該端口,而后由操作系統(tǒng)分配一個(gè)新的端口(Socket)與客戶端進(jìn)行數(shù)據(jù)通信(先握手,然后建立連接,但是使用不同的端口)。不同的Connector實(shí)現(xiàn)可以使用不同的底層結(jié)構(gòu),如Socket Connector、NIO Connector等,也可以使用不同的協(xié)議,如Ssl Connector、AJP Connector,從而在不同的Connector中配置不同的EndPoint和Connection。EndPoint用于連接(Socket)的讀寫(xiě)數(shù)據(jù)(參見(jiàn)深入Jetty源碼之EndPoint),Connection用于關(guān)聯(lián)Request、Response、EndPoint、Server,并將解析出來(lái)的Request、Response傳遞給在Server中注冊(cè)的Handler來(lái)處理(參見(jiàn)深入Jetty源碼之Connection)。在Jetty中Connector的有:SocketConnector、SslSocketConnector、Ajp13SocketConnector、BlockingChannelConnector、SelectChannelConnector、SslSelectChannelConnector、LocalConnector、NestedConnector等,其類圖如下。Connector類圖

Connector接口
首先Connector實(shí)現(xiàn)了LifeCycle接口,在啟動(dòng)Jetty服務(wù)器時(shí),會(huì)調(diào)用其的start方法,用于初始化Connector內(nèi)部狀態(tài),并打開(kāi)Connector以接受客戶端的請(qǐng)求(調(diào)用open方法);而在停止Jetty服務(wù)器時(shí)會(huì)調(diào)用其stop方法,以關(guān)閉Connector以及內(nèi)部元件(如Connection等)以及做一些清理工作。因而open、close方法是Connector中用于處理生命周期的方法;對(duì)每個(gè)Connector都有name字段用于標(biāo)記該Connector,默認(rèn)值為:hostname:port;Connector中還有Server的引用,可以從中獲取ThreadPool,并作為Handler的容器被使用(在創(chuàng)建HttpConnection時(shí),Server實(shí)例作為構(gòu)造函數(shù)參數(shù)傳入,并在handleRequest()方法中將解析出來(lái)的Request、Response傳遞給Server注冊(cè)的Handler);Connector還定義了一些用于配置當(dāng)前Connector的方法,如Buffer Size、Max Idle Time、Low Resource Max Idle Time,以及一些統(tǒng)計(jì)信息,如當(dāng)前Connector總共處理過(guò)的請(qǐng)求數(shù)、總共處理過(guò)的連接數(shù)、當(dāng)前打開(kāi)的連接數(shù)等信息。Connector的接口定義如下:
public interface Connector extends LifeCycle {
// Connector名字,默認(rèn)值hostname:port
String getName();
// 打開(kāi)當(dāng)前Connector
void open() throws IOException;
// 關(guān)閉當(dāng)前Connector
void close() throws IOException;
// 對(duì)Server的引用
void setServer(Server server);
Server getServer();
// 在處理請(qǐng)求消息頭時(shí)使用的Buffer大小
int getRequestHeaderSize();
void setRequestHeaderSize(int size);
// 在處理響應(yīng)消息頭時(shí)使用的Buffer大小
int getResponseHeaderSize();
void setResponseHeaderSize(int size);
// 在處理請(qǐng)求消息內(nèi)容時(shí)使用的Buffer大小
int getRequestBufferSize();
void setRequestBufferSize(int requestBufferSize);
// 在處理響應(yīng)消息內(nèi)容使用的Buffer大小
int getResponseBufferSize();
void setResponseBufferSize(int responseBufferSize);
// 在處理請(qǐng)求消息時(shí)使用的Buffer工廠
Buffers getRequestBuffers();
// 在處理響應(yīng)消息時(shí)使用的Buffer工廠
Buffers getResponseBuffers();
// User Data Constraint的配置可以是None、Integral、Confidential,對(duì)這三種值的解釋:
// None:A value of NONE means that the application does not require any transport guarantees.
// Integral:A value of INTEGRAL means that the application requires the data sent between the client and server to be sent in such a way that it can't be changed in transit.
// Confidential:A value of CONFIDENTIAL means that the application requires the data to be transmitted in a fashion that prevents other entities from observing the contents of the transmission on.
// In most cases, the presence of the INTEGRAL or CONFIDENTIAL flag indicates that the use of SSL is required.參考:這里
// 如果配置了user-data-constraint為Integral或confidential表示所有相應(yīng)請(qǐng)求都會(huì)重定向到使用Integral/Confidential Schema/Port構(gòu)建的新的URL中。
int getIntegralPort();
String getIntegralScheme();
boolean isIntegral(Request request);
int getConfidentialPort();
String getConfidentialScheme();
boolean isConfidential(Request request);
// 在將HttpConnection交給Server中的Handlers處理前,根據(jù)當(dāng)前Connector,自定義一些EndPoint和Request的配置,如設(shè)置EndPoint的MaxIdleTime,Request的timestamp,
// 清除SelectChannelEndPoint中的idleTimestamp,檢查forward頭等。
void customize(EndPoint endpoint, Request request) throws IOException;
// 主要用于SelectChannelConnector中,重置SelectChannelEndPoint中的idleTimestamp,即重新計(jì)時(shí)idle的時(shí)間。
// 它在每個(gè)Request處理結(jié)束,EndPoint還未關(guān)閉,并且當(dāng)前連接屬于keep-alive類型的時(shí)候被調(diào)用。
void persist(EndPoint endpoint) throws IOException;
// 底層的鏈接實(shí)例,如ServerSocket、ServerSocketChannel等。
Object getConnection();
//是否對(duì)"X-Forwarded-For"頭進(jìn)行DNS名字解析
boolean getResolveNames();
// 當(dāng)前Connector綁定的主機(jī)名、端口號(hào)等。貌似在Connector的實(shí)現(xiàn)中沒(méi)有一個(gè)默認(rèn)的主機(jī)名。
// 由于端口號(hào)可以設(shè)置為0,表示由操作系統(tǒng)隨機(jī)的分配一個(gè)還沒(méi)有被使用的端口,因而這里由LocalPort用于存儲(chǔ)Connector實(shí)際上綁定的端口號(hào);
// 其中-1表示這個(gè)Connector還未開(kāi)啟,-2表示Connector已經(jīng)關(guān)閉。
String getHost();
void setHost(String hostname);
void setPort(int port);
int getPort();
int getLocalPort();
// Socket的最大空閑時(shí)間,以及在資源比較少(如線程池中的任務(wù)數(shù)比最大可用線程數(shù)要多)的情況下的最大空閑時(shí)間,當(dāng)空閑時(shí)間超過(guò)這個(gè)時(shí)間后關(guān)閉當(dāng)前連接(Socket)。
int getMaxIdleTime();
void setMaxIdleTime(int ms);
int getLowResourceMaxIdleTime();
void setLowResourceMaxIdleTime(int ms);
// 是否當(dāng)前Connector處于LowResources狀態(tài),即線程池中的任務(wù)數(shù)比最大可用線程數(shù)要多
public boolean isLowResources();
/* ------------------------以下是一些獲取和當(dāng)前Connector相關(guān)的統(tǒng)計(jì)信息------------------------------------ */
// 打開(kāi)或關(guān)閉統(tǒng)計(jì)功能
public void setStatsOn(boolean on);
// 統(tǒng)計(jì)功能的開(kāi)閉狀態(tài)
public boolean getStatsOn();
// 重置統(tǒng)計(jì)數(shù)據(jù),以及統(tǒng)計(jì)開(kāi)始時(shí)間
public void statsReset();
// 統(tǒng)計(jì)信息的開(kāi)啟時(shí)間戳
public long getStatsOnMs();
// 當(dāng)前Connector處理的請(qǐng)求數(shù)
public int getRequests();
// 當(dāng)前Connector接收到過(guò)的連接數(shù)
public int getConnections() ;
// 當(dāng)前Connector所有當(dāng)前還處于打開(kāi)狀態(tài)的連接數(shù)
public int getConnectionsOpen() ;
// 當(dāng)前Connector歷史上同時(shí)處于打開(kāi)狀態(tài)的最大連接數(shù)
public int getConnectionsOpenMax() ;
// 當(dāng)前Connector所有連接的持續(xù)時(shí)間總和
public long getConnectionsDurationTotal();
// 當(dāng)前Connector的最長(zhǎng)連接持續(xù)時(shí)間
public long getConnectionsDurationMax();
// 當(dāng)前Connector平均連接持續(xù)時(shí)間
public double getConnectionsDurationMean() ;
// 當(dāng)前Connector所有連接持續(xù)時(shí)間的標(biāo)準(zhǔn)偏差
public double getConnectionsDurationStdDev() ;
// 當(dāng)前Connector的所有連接的平均請(qǐng)求數(shù)
public double getConnectionsRequestsMean() ;
// 當(dāng)前Connector的所有連接的請(qǐng)求數(shù)標(biāo)準(zhǔn)偏差
public double getConnectionsRequestsStdDev() ;
// 當(dāng)前Connector的所有連接的最大請(qǐng)求數(shù)
public int getConnectionsRequestsMax();
}
// Connector名字,默認(rèn)值hostname:port
String getName();
// 打開(kāi)當(dāng)前Connector
void open() throws IOException;
// 關(guān)閉當(dāng)前Connector
void close() throws IOException;
// 對(duì)Server的引用
void setServer(Server server);
Server getServer();
// 在處理請(qǐng)求消息頭時(shí)使用的Buffer大小
int getRequestHeaderSize();
void setRequestHeaderSize(int size);
// 在處理響應(yīng)消息頭時(shí)使用的Buffer大小
int getResponseHeaderSize();
void setResponseHeaderSize(int size);
// 在處理請(qǐng)求消息內(nèi)容時(shí)使用的Buffer大小
int getRequestBufferSize();
void setRequestBufferSize(int requestBufferSize);
// 在處理響應(yīng)消息內(nèi)容使用的Buffer大小
int getResponseBufferSize();
void setResponseBufferSize(int responseBufferSize);
// 在處理請(qǐng)求消息時(shí)使用的Buffer工廠
Buffers getRequestBuffers();
// 在處理響應(yīng)消息時(shí)使用的Buffer工廠
Buffers getResponseBuffers();
// User Data Constraint的配置可以是None、Integral、Confidential,對(duì)這三種值的解釋:
// None:A value of NONE means that the application does not require any transport guarantees.
// Integral:A value of INTEGRAL means that the application requires the data sent between the client and server to be sent in such a way that it can't be changed in transit.
// Confidential:A value of CONFIDENTIAL means that the application requires the data to be transmitted in a fashion that prevents other entities from observing the contents of the transmission on.
// In most cases, the presence of the INTEGRAL or CONFIDENTIAL flag indicates that the use of SSL is required.參考:這里
// 如果配置了user-data-constraint為Integral或confidential表示所有相應(yīng)請(qǐng)求都會(huì)重定向到使用Integral/Confidential Schema/Port構(gòu)建的新的URL中。
int getIntegralPort();
String getIntegralScheme();
boolean isIntegral(Request request);
int getConfidentialPort();
String getConfidentialScheme();
boolean isConfidential(Request request);
// 在將HttpConnection交給Server中的Handlers處理前,根據(jù)當(dāng)前Connector,自定義一些EndPoint和Request的配置,如設(shè)置EndPoint的MaxIdleTime,Request的timestamp,
// 清除SelectChannelEndPoint中的idleTimestamp,檢查forward頭等。
void customize(EndPoint endpoint, Request request) throws IOException;
// 主要用于SelectChannelConnector中,重置SelectChannelEndPoint中的idleTimestamp,即重新計(jì)時(shí)idle的時(shí)間。
// 它在每個(gè)Request處理結(jié)束,EndPoint還未關(guān)閉,并且當(dāng)前連接屬于keep-alive類型的時(shí)候被調(diào)用。
void persist(EndPoint endpoint) throws IOException;
// 底層的鏈接實(shí)例,如ServerSocket、ServerSocketChannel等。
Object getConnection();
//是否對(duì)"X-Forwarded-For"頭進(jìn)行DNS名字解析
boolean getResolveNames();
// 當(dāng)前Connector綁定的主機(jī)名、端口號(hào)等。貌似在Connector的實(shí)現(xiàn)中沒(méi)有一個(gè)默認(rèn)的主機(jī)名。
// 由于端口號(hào)可以設(shè)置為0,表示由操作系統(tǒng)隨機(jī)的分配一個(gè)還沒(méi)有被使用的端口,因而這里由LocalPort用于存儲(chǔ)Connector實(shí)際上綁定的端口號(hào);
// 其中-1表示這個(gè)Connector還未開(kāi)啟,-2表示Connector已經(jīng)關(guān)閉。
String getHost();
void setHost(String hostname);
void setPort(int port);
int getPort();
int getLocalPort();
// Socket的最大空閑時(shí)間,以及在資源比較少(如線程池中的任務(wù)數(shù)比最大可用線程數(shù)要多)的情況下的最大空閑時(shí)間,當(dāng)空閑時(shí)間超過(guò)這個(gè)時(shí)間后關(guān)閉當(dāng)前連接(Socket)。
int getMaxIdleTime();
void setMaxIdleTime(int ms);
int getLowResourceMaxIdleTime();
void setLowResourceMaxIdleTime(int ms);
// 是否當(dāng)前Connector處于LowResources狀態(tài),即線程池中的任務(wù)數(shù)比最大可用線程數(shù)要多
public boolean isLowResources();
/* ------------------------以下是一些獲取和當(dāng)前Connector相關(guān)的統(tǒng)計(jì)信息------------------------------------ */
// 打開(kāi)或關(guān)閉統(tǒng)計(jì)功能
public void setStatsOn(boolean on);
// 統(tǒng)計(jì)功能的開(kāi)閉狀態(tài)
public boolean getStatsOn();
// 重置統(tǒng)計(jì)數(shù)據(jù),以及統(tǒng)計(jì)開(kāi)始時(shí)間
public void statsReset();
// 統(tǒng)計(jì)信息的開(kāi)啟時(shí)間戳
public long getStatsOnMs();
// 當(dāng)前Connector處理的請(qǐng)求數(shù)
public int getRequests();
// 當(dāng)前Connector接收到過(guò)的連接數(shù)
public int getConnections() ;
// 當(dāng)前Connector所有當(dāng)前還處于打開(kāi)狀態(tài)的連接數(shù)
public int getConnectionsOpen() ;
// 當(dāng)前Connector歷史上同時(shí)處于打開(kāi)狀態(tài)的最大連接數(shù)
public int getConnectionsOpenMax() ;
// 當(dāng)前Connector所有連接的持續(xù)時(shí)間總和
public long getConnectionsDurationTotal();
// 當(dāng)前Connector的最長(zhǎng)連接持續(xù)時(shí)間
public long getConnectionsDurationMax();
// 當(dāng)前Connector平均連接持續(xù)時(shí)間
public double getConnectionsDurationMean() ;
// 當(dāng)前Connector所有連接持續(xù)時(shí)間的標(biāo)準(zhǔn)偏差
public double getConnectionsDurationStdDev() ;
// 當(dāng)前Connector的所有連接的平均請(qǐng)求數(shù)
public double getConnectionsRequestsMean() ;
// 當(dāng)前Connector的所有連接的請(qǐng)求數(shù)標(biāo)準(zhǔn)偏差
public double getConnectionsRequestsStdDev() ;
// 當(dāng)前Connector的所有連接的最大請(qǐng)求數(shù)
public int getConnectionsRequestsMax();
}
AbstractConnector實(shí)現(xiàn)
Jetty中所有的Connector都繼承自AbstractConnector,而它自身繼承自HttpBuffers,HttpBuffers包含了Request、Response的Buffer工廠的創(chuàng)建以及相應(yīng)Size的配置。AbstractConnector還包含了Name、Server、maxIdleTime以及一些統(tǒng)計(jì)信息的引用,用于實(shí)現(xiàn)Connector接口中的方法,只是一些Get、Set方法,不詳述。除了Connector接口相關(guān)的配置,AbstractConnector還為定義了兩個(gè)字段:_acceptQueueSize用于表示ServerSocket 或ServerSocketChannel中最大可等待的請(qǐng)求數(shù),_acceptors用于表示用于調(diào)用ServerSocket或ServerSocketChannel中accept方法的線程數(shù),建議這個(gè)數(shù)字小于或等于可用處理器的2倍。在AbstractConnector中還定義了Acceptor內(nèi)部類,它實(shí)現(xiàn)了Runnable接口,在其run方法實(shí)現(xiàn)中,它將自己的Thread實(shí)例賦值給AbstractConnector中的_acceptorThread數(shù)組中acceptor號(hào)對(duì)應(yīng)的bucket,并更新線程名為:<name> Acceptor<index> <Connector.toString>。然后根據(jù)配置的_acceptorPriorityOffset設(shè)置當(dāng)前線程的priority。只要當(dāng)前Connector處于Running狀態(tài),并且底層鏈接實(shí)例不為null,不斷的調(diào)用accept方法()。在退出的finally語(yǔ)句快中清理_acceptorThread數(shù)組中相應(yīng)的Bucket值為null,并將線程原來(lái)的Name、Priority設(shè)置回來(lái)。
AbstractConnector實(shí)現(xiàn)了doStart()方法,它首先保證Server實(shí)例的存在;然后打開(kāi)當(dāng)前Connector(調(diào)用其open()方法),并調(diào)用父類的doStart方法(這里是HttpBuffers,用于初始化對(duì)應(yīng)的Buffers);如果沒(méi)有自定義的ThreadPool,則從Server中獲取ThreadPool;最后根據(jù)acceptors的值創(chuàng)建_acceptorThread數(shù)組,將acceptors個(gè)Acceptor實(shí)例dispatch給ThreadPool。在doStop方法實(shí)現(xiàn)中,它首先調(diào)用close方法,然后對(duì)非Server中的ThreadPool調(diào)用其stop方法,再調(diào)用父類的doStop方法清理Buffers的引用,最后遍歷_acceptorThread數(shù)據(jù),調(diào)用每個(gè)Thread的interrupt方法。
在各個(gè)子類的accept方法實(shí)現(xiàn)中,他們?cè)讷@取客戶端過(guò)來(lái)的Socket連接后,都會(huì)對(duì)該Socket做一些配置,即調(diào)用AbstractConnector的configure方法,它首先設(shè)置Socket的TCP_NODELAY為true,即禁用Nagle算法(關(guān)于禁用的理由可以參考:http://jerrypeng.me/2013/08/mythical-40ms-delay-and-tcp-nodelay/#sec-4-2,簡(jiǎn)單的,如果該值為false,則TCP的數(shù)據(jù)包要么達(dá)到TCP Segment Size,要么收到一個(gè)Ack,才會(huì)發(fā)送出去,即有Delay);然后如果設(shè)置了_soLingerTime,則開(kāi)啟Socket中SO_LINGER選項(xiàng),否則,關(guān)閉該選項(xiàng)(SO_LINGER選項(xiàng)用于控制關(guān)閉一個(gè)Socket的行為,如果開(kāi)啟了該選項(xiàng),則在關(guān)閉Socket時(shí)會(huì)等待_soLingerTime時(shí)間,此時(shí)如果有數(shù)據(jù)還未發(fā)送完,則會(huì)發(fā)送這些數(shù)據(jù);如果關(guān)閉了該選項(xiàng),則Socket的關(guān)閉會(huì)立即返回,此時(shí)也有可能繼續(xù)發(fā)送未發(fā)送完成的數(shù)據(jù),具體參考:http://blog.csdn.net/factor2000/article/details/3929816)。
在ServerSocket和ServerSocketChannel中還有一個(gè)SO_REUSEADDR的配置,一般來(lái)說(shuō)當(dāng)一個(gè)端口被釋放后會(huì)等待兩分鐘再被使用,此時(shí)如果重啟服務(wù)器,可能會(huì)導(dǎo)致啟動(dòng)時(shí)的綁定錯(cuò)誤,設(shè)置該值可以讓端口釋放后可以立即被使用(具體參考:http://www.cnblogs.com/mydomain/archive/2011/08/23/2150567.html)。在AbstractConnector中可以使用setReuseAddress方法來(lái)配置,默認(rèn)該值設(shè)置為true。
AbstractConnector中還實(shí)現(xiàn)了customize方法,它在forwarded設(shè)置為true的情況下設(shè)置相應(yīng)的attribute:javax.servlet.request.cipher_suite, javax.servlet.request.ssl_session_id,以及Request中對(duì)應(yīng)Host、Server等頭信息。這個(gè)邏輯具體含義目前還不是很了解。。。。
最后關(guān)于統(tǒng)計(jì)數(shù)據(jù)的更新方法,AbstractConnector定義了如下方法:
protected void connectionOpened(Connection connection)
protected void connectionUpgraded(Connection oldConnection, Connection newConnection)
protected void connectionClosed(Connection connection)
protected void connectionUpgraded(Connection oldConnection, Connection newConnection)
protected void connectionClosed(Connection connection)
SocketConnector實(shí)現(xiàn)
有了AbstractConnector的實(shí)現(xiàn),SocketConnector的實(shí)現(xiàn)就變的非常簡(jiǎn)單了,它保存了一個(gè)EndPoint的Set,表示所有在這個(gè)Connector下正在使用的EndPoint,然后是ServerSocket,在open方法中創(chuàng)建,并在getConnection()方法中返回,還有一個(gè)localPort字段,當(dāng)ServerSocket被創(chuàng)建時(shí)從ServerSocket實(shí)例中獲取,并在getLocalPort()方法中返回。在close方法中關(guān)閉ServerSocket,并設(shè)置localPort為-2;在accept方法中,調(diào)用ServerSocket的accept方法,返回一個(gè)Socket,調(diào)用configure方法對(duì)新創(chuàng)建的Socket做一些基本的配置,然后使用該Socket創(chuàng)建ConnectorEndPoint,并調(diào)用其dispatch方法;在customize方法中,在調(diào)用AbstractConnector的customize方法的同時(shí)還設(shè)置ConnectorEndPoint的MaxIdleTime,即設(shè)置Socket的SO_TIMEOUT選項(xiàng),用于配置該Socket的空閑可等待時(shí)間;在doStart中會(huì)先清理ConnectorEndPoint的集合,而在doStop中會(huì)關(guān)閉所有還處于打開(kāi)狀態(tài)的ConnectorEndPoint。SelectChannelConnector實(shí)現(xiàn)
SelectChannelConnector內(nèi)部使用ServerSocketChannel,在open方法中創(chuàng)建ServerSocketChannel,配置其為非blocking模式,并設(shè)置localPort值;在accept方法中調(diào)用ServerSocket的accept方法獲得一個(gè)SocketChannel,配置該Channel為非blocking模式,調(diào)用AbstractChannel的configure方法做相應(yīng)Socket配置,最后將該SocketChannel注冊(cè)給ConnectorSelectManager;在doStart方法中,它會(huì)初始化ConnectorSelectManager的SelectSets值為acceptors值、MaxIdleTime、LowResourceConnections、LowResourcesMaxIdleTime等值,并啟動(dòng)該Manager,并dispatch acceptors個(gè)線程,不斷的調(diào)用Manager的doSelect方法;在close方法中會(huì)先stop ConnectorSelectManager,然后關(guān)閉ServerSocketChannel,設(shè)置localPort為-2;在customize方法中會(huì)清除SelectChannelEndPoint的idleTimestamp,重置其MaxIdleTime以及重置Request中的timestamp的值;在persist方法中會(huì)重置SelectChannelEndPoint中idleTimestamp的值。BlockingChannelConnector實(shí)現(xiàn)
BlockingChannelConnector實(shí)現(xiàn)類似SocketConnector,不同的是它使用ServerSocketChannel,并且其EndPoint為BlockingChannelEndPoint。所不同的是它需要在doStart方法中啟動(dòng)一個(gè)線程不斷的檢查所有還在connections集合中的BlockingChannelEndPoint是否已經(jīng)超時(shí),每400ms檢查一次,如果超時(shí)則關(guān)閉該EndPoint。其他的Connector的實(shí)現(xiàn)都比較類似,而SSL相關(guān)的Connector需要也只是加入了SSL相關(guān)的邏輯,這里不再贅述。