【tomcat啟動類Bootstrap】
t1.tomcat的人口函數(shù),啟動類
org.apache.catalina.startup. Bootstrap.java Main函數(shù)
t2.Bootstrap類
初始化 ClassLoader, 然后利用 Java Reflection 調(diào)用 Catalina 類來啟動 tomcat server
【tomcat擴(kuò)展-日志】
a1.private static Log log = LogFactory.getLog(Bootstrap.class);
日志可以定義為private 和static
a2.只在本類中使用的方法,使用private,降低訪問權(quán)限,需要的時候,再考慮重構(gòu)或者提高訪問權(quán)限public
a.日志打印前加if(log.isInfoEnabled())
如果代碼中含有l(wèi)ogger.debug(“string”);此類語句,盡管在log4j.xml配置文件中對該類logger的level為 ERROR,但是仍然會產(chǎn)生較大的內(nèi)存開銷,通常是所要輸出的string的幾十倍甚至上百倍大小,對內(nèi)存開銷非常大。優(yōu)化方法為:使用logger進(jìn)行 判斷。
2010-3-30
【tomcat擴(kuò)展-classloader】
a3.如果兩個類屬于同一個包下,但是由不同的classloader加載,那么他們也不能互訪default類型方法,屬性
a4.classloader:與C或C++編寫的程序不同,Java程序并不是一個可執(zhí)行文件,而是由許多獨(dú)立的類文件組成,每一個文件基本上 對應(yīng)于一個類。此外,這些類文件并非立即全部都裝入內(nèi)存,而是根據(jù)程序需要裝入內(nèi)存。ClassLoader是JVM中將類裝入內(nèi)存的那部分
a5.定制的ClassLoader應(yīng)用:
1.在執(zhí)行非置信代碼之前,自動驗(yàn)證數(shù)字簽名
2.使用用戶提供的密碼透明地解密代碼
3.動態(tài)地創(chuàng)建符合用戶特定需要的定制化構(gòu)建類
4.任何您認(rèn)為可以生成Java字節(jié)碼的內(nèi)容都可以集成到應(yīng)用程序中
a6.findClass方法是創(chuàng)建定制的ClassLoader時唯一需要覆蓋的方法。
ClassLoader loadClass方法
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
a7.ClassLoader(CCL)的任務(wù)是確保代碼被編譯和更新。
下面描述了它的工作方式:1、當(dāng)請求一個類時,先查看它是否在磁盤的當(dāng)前目錄或相應(yīng)的子目錄。
2、如果該類不存在,但源碼中有,那么調(diào)用Java編譯器來生成類文件。
3、如果該類已存在,檢查它是否比源碼舊。如果是,調(diào)用Java編譯器來重新生成類文件。
4、如果編譯失敗,或者由于其它原因不能從現(xiàn)有的源碼中生成類文件,返回ClassNotFoundException。
5、如果仍然沒有該類,也許它在其它庫中,所以調(diào)用findSystemClass來尋找該類。
6、如果還是沒有,則返回ClassNotFoundException。
7、否則,返回該類。
8、調(diào)用findLoadedClass來查看是否存在已裝入的類。
9、如果沒有,那么采用那種特殊的神奇方式來獲取原始字節(jié)。
10、如果已有原始字節(jié),調(diào)用defineClass將它們轉(zhuǎn)換成Class對象。
11、如果沒有原始字節(jié),然后調(diào)用findSystemClass查看是否從本地文件系統(tǒng)獲取類。
12、如果resolve參數(shù)是true,那么調(diào)用resolveClass解析Class對象。
13、如果還沒有類,返回ClassNotFoundException。
14、否則,將類返回給調(diào)用程序。
【tomcat啟動類classloader】
t3.tomcat自定義了三個類,catalinaLoader commonLoader,sharedLoader
Common - 載入$CATALINA_HOME/common/...它們對TOMCAT和所有的WEB APP都可見
Catalina - 載入$CATALINA_HOME/server/..它們僅對TOMCAT可見,對所有的WEB APP都不可見
Shared-載入$CATALINA_HOME/shared/它們僅對所有WEB APP可見,對TOMCAT不可見(也不必見)
t4.Bootstrap通過反射初始化Catalina類,
反射調(diào)用Catalina方法setParentClassLoader,傳遞SharedClassloader
反射call Catalina方法load 利用server.xml中的配置初始化Service,Server,Engine,Host
反射call Catalina方法start Start the new server 該server是通過 解析xml文件生成的org.apache.catalina.core.StandardServer類
【tomcat-xml解析】
1.Tomcat取了Digester中的interface和幾個Rule,并且自己實(shí)現(xiàn)了一些 Rule 來解析xml.
2.tomcat解析xml創(chuàng)建以下幾個類
Server:
org.apache.catalina.core.StandardServer
Resources:
org.apache.catalina.deploy.NamingResources
Server's Listener:( 監(jiān)聽server事件)
org.apache.catalina.core.AprLifecycleListener
org.apache.catalina.core.JasperListener
org.apache.catalina.mbeans.ServerLifecycleListener
org.apache.catalina.mbeans.GlobalResourcesLifecycleListener
Service:
org.apache.catalina.core.StandardService
Executor:
org.apache.catalina.core.StandardThreadExecutor
Engine:
org.apache.catalina.core.StandardEngine
Connector:
org.apache.catalina.connector.Connector
【tomcat-流程】
3.StandardServer啟動StandardService,StandardService啟動Connector,
Connector啟動Http11Protocol,Http11Protocol啟動JIoEndpoint,
JioEndpoint啟動server Socket,listern 8080端口,處理http請求
4.Http11Processor
Processes HTTP requests.
由http11ConnectionHandler調(diào)用,Http11ConnectionHandler由JioEndpoint中的Work 調(diào)用
5.A connector passes the request and reponse objects to the Container by calling the Container interface's invoke method
public void invoke(Request request, Response response)
throws IOException, ServletException;
inside the invoke method ,the container loads the servlet class,call its sevice method ,manage sessions,etc.
6.Connector 方法initialize中
// Initializa adapter
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
adapter通過protocolHandler(Http11Protocol)傳給Http11Processor,
Http11Processor解析,create request和response,通過adapter傳送給Container
7.Tomcat使用Pipeline模式在各層容器間傳遞請求,將請求通過管道依次通過Engine,Host,Context和 Wrapper。另外,每一個容器
都可以設(shè)置一系列的Valve去對請求進(jìn)行攔 截,就像管道中的閥一樣對請求的行為進(jìn)行一些干涉。
2010-3-31
【tomcat-流程】
1.tomcat的pipeline/valve是標(biāo)準(zhǔn)的責(zé)任鏈模式,每個級別的容器中pipeline所有的valve都完成動作后會將 request/response傳到下一個容器的pipeline中的valve,
這樣一直傳遞下去直到Wrapper的BaseValve.
Ps:每個容器的BaseValve會調(diào)用下個容器的起始valve
2.StandardEngine
屬性Pipeline pipeline = new StandardPipeline(this);
構(gòu)造函數(shù)里會設(shè)置最底層的閥門
pipeline.setBasic(new StandardEngineValve());
如果需要設(shè)置新閥門處理需求,只需要調(diào)用 pipeline.addValve(Valve valve);
3.CoyoteAdapter中會執(zhí)行
connector.getContainer().getPipeline().getFirst().invoke(request, response);
該行代碼會一層一層調(diào)用添加的閥門,處理下去.
2010-4-1
【tomcat-流程】
1.jk插件負(fù)責(zé)tomcat和其它http容器進(jìn)行通信
2.連接器協(xié)議AJP/1.3是tomcat用來與其它http容器進(jìn)行連接的協(xié)議
3.把指定Context的classloader付給當(dāng)前線程。
Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader()); 這樣request就只看見指定的context下面的classes和jar包,而看不見tomcat本身的類。
2010-4-7
【tomcat-socke與worker線程】
/**
* Process an incoming TCP/IP connection on the specified socket. Any
* exception that occurs during processing must be logged and swallowed.
* <b>NOTE</b>: This method is called from our Connector's thread. We
* must assign it to our own thread so that multiple simultaneous
* requests can be handled.
* @param socket TCP socket to process
*/
synchronized void assign(Socket socket) {
// Wait for the Processor to get the previous Socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Store the newly available Socket and notify our thread
this.socket = socket;
available = true;
notifyAll();
}
/**
* Await a newly assigned Socket from our Connector, or <code>null</code
* if we are supposed to shut down.
*/
private synchronized Socket await() {
// Wait for the Connector to provide a new Socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Notify the Connector that we have received this Socket
Socket socket = this.socket;
available = false;
notifyAll();
return (socket);
}
連接器線程調(diào)用worker類的assign類,worker類的執(zhí)行線程run方法會調(diào)用await方法獲取socket,通過 available變量的設(shè)置和wait/notify方法來協(xié)調(diào)彼此的操作。當(dāng)連接器線程未傳輸socket,worker類線程就執(zhí)行wait等待,
當(dāng)worker類執(zhí)行線程在處理忙的時候,連接器線程wait。
一直以來都是用tomcat做web服務(wù)器進(jìn)行開發(fā),很想知道其內(nèi)部的一些原理和實(shí)現(xiàn)(雖然很多人說知道原理又不能當(dāng)飯吃)。今天跟蹤調(diào)試了源碼的啟動程序(關(guān)于源碼的eclipse的導(dǎo)入以及ant的構(gòu)建,網(wǎng)上有大把的資料,google一下就ok了),總算知道點(diǎn)大致的啟動步驟,有些淺顯的領(lǐng)悟分享一下: org.apache.catalina.startup.Bootstrap作為啟動入口,此類的main函數(shù): 1.首先創(chuàng)建一個自身的實(shí)例(如果此類的實(shí)例變量:private static Bootstrap daemon為空的話);
2.然后調(diào)用init()方法,此方法的主要工作就是反射得到org.apache.catalina.startup.Catalina的實(shí)例,同時把classLoader通過Catalina的setParentClassLoader方法賦值。
3.接著調(diào)用load(args)方法,此方法反射調(diào)用Catalina的load(args),根據(jù)傳遞的參數(shù)設(shè)置部分屬性值之后,會接著執(zhí)行Catalina的load()方法。 在這個無參的方法里通過Digester組件(Jakarta Commons Digester是apache的一個解析處理xml的開源項(xiàng)目,開始我還以為巧合,因?yàn)閟truts的ActionServlet也是使用此組件解析,后來才知道tomcat的一個主力也是struts的創(chuàng)造者之一)解析conf/server.xml等xml文件,初始化一系列的參數(shù)。
4.接著Bootstrap的start()方法反射調(diào)用Catalina的start()方法,此方法通過調(diào)用xml解析處理后得到的server:org.apache.catalina.core.StandardServer的start()方法進(jìn)入其所擁有的Lifecycle service:org.apache.catalina.core.StandardService的start()方法,接著調(diào)用Lifecycle Container:org.apache.catalina.core.StandardEngine的start()方法,初始化一堆東西之后到達(dá)旅途的終點(diǎn),StandardEngine的父類:org.apache.catalina.core.ContainerBase的start(),這個方法是通過自身的threadStart()方法啟動了一個容器線程: thread = new Thread(new ContainerBackgroundProcessor(), threadName); thread.setDaemon(true); thread.start();
5.上面的繁文的簡化大致是:Bootstrap(init,load,start)--> Catalina(start)--> StandardServer(start)--> StandardService(start)--> StandardEngine(start)--> ContainerBase(start, threadStart)
至此終于看到雙擊.bat或者執(zhí)行.sh背后的一點(diǎn)點(diǎn)東西了(我是跟蹤的6.0.20的源碼,可能之前的版本的有所不同)。 |