本文接下來介紹tomcat的默認(rèn)連接器,Tomcat中的默認(rèn)連接器必須滿足以下要求:
-
實(shí)現(xiàn)org.apache.catalina.Connector接口
-
負(fù)責(zé)創(chuàng)建實(shí)現(xiàn)org.apache.catalina.Request接口的Request對(duì)象
-
負(fù)責(zé)創(chuàng)建實(shí)現(xiàn)org.apache.catalina.Response接口的Response對(duì)象
org.apache.catalina.Connector接口最重要的方法是getContainer() 、setContainer()、creatRequest()、 creatResponse(),setContainer()方法用于設(shè)置相關(guān)聯(lián)的servlet容器,getContainer()方法獲取相關(guān)連的servlet容器,creatRequest()方法為http請(qǐng)求創(chuàng)建request對(duì)象,creatResponse()方法創(chuàng)建response對(duì)象
下面來分析HttpConnector類實(shí)現(xiàn),HttpConnector類同時(shí)實(shí)現(xiàn)了org.apache.catalina.Connector接口org.apache.catalina.Lifecycle接口(用于生命周期管理)、java.lang.Runnable接口(多線程接口)
在HttpConnector對(duì)象的初始化方法initialize()里面,調(diào)用私有方法open(),創(chuàng)建ServerSocket實(shí)例
private ServerSocket open() throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { // Acquire the server socket factory for this Connector ServerSocketFactory factory = getFactory(); // If no address is specified, open a connection on all addresses if (address == null ) { log(sm.getString( "httpConnector.allAddresses" )); try { return (factory.createSocket(port, acceptCount)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + port); } } // Open a server socket on the specified address try { InetAddress is = InetAddress.getByName(address); log(sm.getString( "httpConnector.anAddress" , address)); try { return (factory.createSocket(port, acceptCount, is)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + address + ":" + port); } } catch (Exception e) { log(sm.getString( "httpConnector.noAddress" , address)); try { return (factory.createSocket(port, acceptCount)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + port); } } }
上面的ServerSocketFactory factory = getFactory()顯然是創(chuàng)建ServerSocket實(shí)例的工廠,方法如下
/** * Return the server socket factory used by this Container. */ public ServerSocketFactory getFactory() { if ( this .factory == null ) { synchronized ( this ) { this .factory = new DefaultServerSocketFactory(); } } return ( this .factory); }
工廠類DefaultServerSocketFactory實(shí)現(xiàn)了ServerSocketFactory接口
public final class DefaultServerSocketFactory implements ServerSocketFactory { public ServerSocket createSocket ( int port) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { return ( new ServerSocket(port)); } public ServerSocket createSocket ( int port, int backlog) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { return ( new ServerSocket(port, backlog)); } public ServerSocket createSocket ( int port, int backlog, InetAddress ifAddress) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { return ( new ServerSocket(port, backlog, ifAddress)); } }
下面接著分析用于生命周期的start()方法
/** * Begin processing requests via this Connector. * * @exception LifecycleException if a fatal startup error occurs */ public void start() throws LifecycleException { // Validate and update our current state if (started) throw new LifecycleException (sm.getString( "httpConnector.alreadyStarted" )); threadName = "HttpConnector[" + port + "]" ; lifecycle.fireLifecycleEvent(START_EVENT, null ); started = true ; // Start our background thread threadStart(); // Create the specified minimum number of processors while (curProcessors < minProcessors) { if ((maxProcessors > 0) && (curProcessors >= maxProcessors)) break ; HttpProcessor processor = newProcessor(); recycle(processor); } }
首先是啟動(dòng)HttpConnector連接器線程,然后是初始化最少數(shù)量的HttpProcessor處理器入棧
/** * Start the background processing thread. */ private void threadStart() { log(sm.getString( "httpConnector.starting" )); thread = new Thread( this , threadName); thread.setDaemon( true ); thread.start(); }
由于HttpConnector連接器實(shí)現(xiàn)了java.lang.Runnable接口,我們分析它的run()方法實(shí)現(xiàn)
/** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { // Loop until we receive a shutdown command while (! stopped) { // Accept the next incoming connection from the server socket Socket socket = null ; try { // if (debug >= 3) // log("run: Waiting on serverSocket.accept()"); socket = serverSocket.accept(); // if (debug >= 3) // log("run: Returned from serverSocket.accept()"); if (connectionTimeout > 0 ) socket.setSoTimeout(connectionTimeout); socket.setTcpNoDelay(tcpNoDelay); } catch (AccessControlException ace) { log( "socket accept security exception" , ace); continue ; } catch (IOException e) { // if (debug >= 3) // log("run: Accept returned IOException", e); try { // If reopening fails, exit synchronized (threadSync) { if (started && ! stopped) log( "accept error: " , e); if (! stopped) { // if (debug >= 3) // log("run: Closing server socket"); serverSocket.close(); // if (debug >= 3) // log("run: Reopening server socket"); serverSocket = open(); } } // if (debug >= 3) // log("run: IOException processing completed"); } catch (IOException ioe) { log( "socket reopen, io problem: " , ioe); break ; } catch (KeyStoreException kse) { log( "socket reopen, keystore problem: " , kse); break ; } catch (NoSuchAlgorithmException nsae) { log( "socket reopen, keystore algorithm problem: " , nsae); break ; } catch (CertificateException ce) { log( "socket reopen, certificate problem: " , ce); break ; } catch (UnrecoverableKeyException uke) { log( "socket reopen, unrecoverable key: " , uke); break ; } catch (KeyManagementException kme) { log( "socket reopen, key management problem: " , kme); break ; } continue ; } // Hand this socket off to an appropriate processor HttpProcessor processor = createProcessor(); if (processor == null ) { try { log(sm.getString( "httpConnector.noProcessor" )); socket.close(); } catch (IOException e) { ; } continue ; } // if (debug >= 3) // log("run: Assigning socket to processor " + processor); processor.assign(socket); // The processor will recycle itself when it finishes } // Notify the threadStop() method that we have shut ourselves down // if (debug >= 3) // log("run: Notifying threadStop() that we have shut down"); synchronized (threadSync) { threadSync.notifyAll(); } }
上面方法中,監(jiān)聽客戶端的http請(qǐng)求,當(dāng)監(jiān)聽到http請(qǐng)求時(shí),獲取Socket實(shí)例,然后委派給HttpProcessor對(duì)象進(jìn)行處理(處理器線程吧),最后是如果收到停止連接器線程命令, 則事件通知可以停止線程了
在上面我們還沒有來得及分析HttpProcessor對(duì)象的初始化相關(guān),所以要重新回到start()方法(源碼分析有時(shí)要跟蹤方法中對(duì)多個(gè)其他方法的調(diào)用,深度優(yōu)先則顧此失彼,難以兼顧;而廣度優(yōu)先則不便縱向深入)
// Create the specified minimum number of processors while (curProcessors < minProcessors) { if ((maxProcessors > 0) && (curProcessors >= maxProcessors)) break ; HttpProcessor processor = newProcessor(); recycle(processor); }
這里是創(chuàng)建最少數(shù)量的HttpProcessor處理器并入棧,我們先分析newProcessor()方法的實(shí)現(xiàn)
/** * Create and return a new processor suitable for processing HTTP * requests and returning the corresponding responses. */ private HttpProcessor newProcessor() { // if (debug >= 2) // log("newProcessor: Creating new processor"); HttpProcessor processor = new HttpProcessor( this , curProcessors++ ); if (processor instanceof Lifecycle) { try { ((Lifecycle) processor).start(); } catch (LifecycleException e) { log( "newProcessor" , e); return ( null ); } } created.addElement(processor); return (processor); }
我們可以看到,這里主要是實(shí)例化HttpProcessor對(duì)象,傳入HttpConnector實(shí)例本身(里面要用到HttpConnector對(duì)象的創(chuàng)建Request對(duì)象方法和創(chuàng)建Response對(duì)象方法),然后向上轉(zhuǎn)型為L(zhǎng)ifecycle接口類型,并調(diào)用它的start()方法,接著Vector created = new Vector()成員變量添加該HttpProcessor對(duì)象(Vector實(shí)現(xiàn)List接口,內(nèi)部采用數(shù)組實(shí)現(xiàn),其操作方法支持線程同步),最后返回實(shí)例
/** * Recycle the specified Processor so that it can be used again. * * @param processor The processor to be recycled */ void recycle(HttpProcessor processor) { // if (debug >= 2) // log("recycle: Recycling processor " + processor); processors.push(processor); }
這里將HttpProcessor對(duì)象入棧,成員變量Stack processors = new Stack()繼承自 Vector ,是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu)
我們現(xiàn)在來分析run()方法里面的相關(guān)源碼,也許更容易理解
/** * Create (or allocate) and return an available processor for use in * processing a specific HTTP request, if possible. If the maximum * allowed processors have already been created and are in use, return * <code>null</code> instead. */ private HttpProcessor createProcessor() { synchronized (processors) { if (processors.size() > 0 ) { // if (debug >= 2) // log("createProcessor: Reusing existing processor"); return ((HttpProcessor) processors.pop()); } if ((maxProcessors > 0) && (curProcessors < maxProcessors)) { // if (debug >= 2) // log("createProcessor: Creating new processor"); return (newProcessor()); } else { if (maxProcessors < 0 ) { // if (debug >= 2) // log("createProcessor: Creating new processor"); return (newProcessor()); } else { // if (debug >= 2) // log("createProcessor: Cannot create new processor"); return ( null ); } } } }
這里是從Stack processors = new Stack()成員變量里面獲取HttpProcessor對(duì)象 ,后面的代碼不用多加解釋了吧,你懂的!
后面那段代碼是干嘛的
// Notify the threadStop() method that we have shut ourselves down // if (debug >= 3) // log("run: Notifying threadStop() that we have shut down"); synchronized (threadSync) { threadSync.notifyAll(); }
我們看到threadStop()方法里面的代碼,可以看出上面的代碼塊是用來通知線程停止的
/** * Stop the background processing thread. */ private void threadStop() { log(sm.getString( "httpConnector.stopping" )); stopped = true ; try { threadSync.wait( 5000 ); } catch (InterruptedException e) { ; } thread = null ; }
由于HttpProcessor處理器類的源碼分析相對(duì)獨(dú)立,加上篇幅還比較多,因此本文先到這里,下文繼續(xù)……
---------------------------------------------------------------------------?
本系列How Tomcat Works系本人原創(chuàng)?
轉(zhuǎn)載請(qǐng)注明出處 博客園 刺猬的溫馴?
本人郵箱: chenying998179 # 163.com ( #改為@ )
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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