Tomcat系統(tǒng)架構分析
Tomcat 的結構很復雜,但是Tomcat也非常的模塊化,找到了Tomcat 最核心的模塊,就抓住Tomcat的“七寸”。
Tomcat 整體結構
Tomcat的總體結構從外到內(nèi)進行分布,最大范圍的服務容器是Server組件,Service服務組件(可以有多個同時存在),Connector(連接器)、Container(容器服務),其他組件:Jasper(Jasper解析)、Naming(命名服務)、Session(會話管理)、Logging(日志管理)、JMX(Java 管理器擴展服務)、Websocket(交互服務)。
Tomcat總體結構圖
從上圖中可以看出 Tomcat 的心臟是兩個組件:Connector 和
Container,關于這兩個組件將在后面詳細介紹。
Connector 組件是可以被替換,這樣可以提供給服務器設計者更多的選擇,因為這個組件是如此重要,不僅跟服務器的設計的本身,而且和不同的應用場景也十分相關,所以一個 Container 可以選擇對應多個 Connector。
多個 Connector 和一個 Container 就形成了一個 Service。
Service的概念大家都很熟悉了,有了 Service 就可以對外提供服務了,但是
Service 還要一個生存的環(huán)境,必須要有人能夠給她生命、掌握其生死大權,那就非 Server 莫屬了。所以整個 Tomcat 的生命周期由Server 控制。
以 Service 作為“婚姻”
我們將 Tomcat 中 Connector、Container 作為一個整體比作一對情
侶的話,Connector 主要負責對外交流,可以比作為Boy,Container
主要處理 Connector 接受的請求,主要是處理內(nèi)部事務,可以比作
為 Girl。那么這個 Service 就是連接這對男女的結婚證了。是
Service 將它們連接在一起,共同組成一個家庭。當然要組成一個家
庭還要很多其它的元素。
說白了,Service 只是在 Connector 和 Container 外面多包一層,
把它們組裝在一起,向外面提供服務,一個 Service 可以設置多個
Connector,但是只能有一個 Container 容器。這個 Service 接口的
方法列表如下:
1) Service 接口
方法列表
從 Service 接口中定義的方法中可以看出,它主要是為了關聯(lián)Connector 和 Container,同時會初始化它下面的其它組件,注意接口中它并沒有規(guī)定一定要控制它下面的組件的生命周期。所有組件的生命周期在一個 Lifecycle 的接口中控制,這里用到了一個重要的設計模式,關于這個接口將在后面介紹。
Tomcat 中 Service 接口的標準實現(xiàn)類是 StandardService 它不僅
實現(xiàn)了 Service 借口同時還實現(xiàn)了 Lifecycle 接口,這樣它就可以控制它下面的組件的生命周期了。StandardService 類結構圖如下
2) StandardService 的類結構圖
方法列表
從上圖中可以看出除了 Service 接口的方法的實現(xiàn)以及控制組件生命周期的 Lifecycle 接口的實現(xiàn),還有幾個方法是用于在事件監(jiān)聽的方法的實現(xiàn),不僅是這個 Service 組件,Tomcat中其它組件也同樣有這幾個方法,這也是一個典型的設計模式,將在后面介紹。
下面看一下 StandardService 中主要的幾個方法實現(xiàn)的代碼,下面是
setContainer 和 addConnector 方法的源碼:
3) StandardService. SetContainer
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 (started && (this.container != null) && (this.container instanceof Lifecycle){
try {
((Lifecycle) this.container).start();
} catch (LifecycleException e) {
;
}
}
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++)
connectors[i].setContainer(this.container);
}
if (started && (oldContainer != null) && (oldContainer instanceof
Lifecycle)) {
try {
((Lifecycle) oldContainer).stop();
} catch (LifecycleException e) {
;
}
}
support.firePropertyChange("container", oldContainer, this.container);
}
這段代碼很簡單,其實就是先判斷當前的這個 Service 有沒有已經(jīng)關聯(lián)了 Container,如果已經(jīng)關聯(lián)了,那么去掉這個關聯(lián)關系——oldContainer.setService(null)。如果這個 oldContainer 已經(jīng)被啟動了,結束它的生命周期。然后再替換新的關聯(lián)、再初始化并開始這個新的 Container 的生命周期。最后將這個過程通知感興趣的事件監(jiān)
聽程序。這里值得注意的地方就是,修改 Container 時要將新的Container 關聯(lián)到每個 Connector,還好 Container 和 Connector 沒有雙向關聯(lián),不然這個關聯(lián)關系將會很難維護。
4) StandardService. addConnector
public void addConnector(Connector connector) {
synchronized (connectors) {
connector.setContainer(this.container);
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 (initialized) {
try {
connector.initialize();
} catch (LifecycleException e) {
e.printStackTrace(System.err);
}
}
if (started && (connector instanceof Lifecycle)) {
try {
((Lifecycle) connector).start();
} catch (LifecycleException e) {
;
}
}
support.firePropertyChange("connector", null, connector);
}
}
上面是 addConnector 方法,這個方法也很簡單,首先是設置關聯(lián)關系,然后是初始化工作,開始新的生命周期。這里值得一提的是,注意 Connector 用的是數(shù)組而不是 List 集合,這個從性能角度考慮可以理解,有趣的是這里用了數(shù)組但是并沒有向我們平常那樣,一開始就分配一個固定大小的數(shù)組,它這里的實現(xiàn)機制是:重新創(chuàng)建一個當前大小的數(shù)組對象,然后將原來的數(shù)組對象 copy 到新的數(shù)組中,這種方式實現(xiàn)了類似的動態(tài)數(shù)組的功能,這種實現(xiàn)方式,值得我們以后拿來借鑒。
最新的 Tomcat6 中 StandardService 也基本沒有變化,但是從Tomcat5 開始 Service、Server 和容器類都繼承了MBeanRegistration 接口,Mbeans 的管理更加合理。
以 Server 為“居”
前面說一對情侶因為 Service 而成為一對夫妻,有了能夠組成一個家庭的基本條件,但是它們還要有個實體的家,這是它們在社會上生存之本,有了家它們就可以安心的為人民服務了,一起為社會創(chuàng)造財富。
Server 要完成的任務很簡單,就是要能夠提供一個接口讓其它程序能夠訪問到這個 Service 集合、同時要維護它所包含的所有 Service 的生命周期,包括如何初始化、如何結束服務、如何找到別人要訪問的 Service。
還有其它的一些次要的任務,如您住在這個地方去登記啊、可能還有要配合當?shù)貦C關日常的安全檢查什么
的。
Server 的類結構圖如下:
1) Server 的類結構圖
它的標準實現(xiàn)類 StandardServer 實現(xiàn)了上面這些方法,同時也實現(xiàn)Lifecycle、MbeanRegistration 兩個接口的所有方法,下面主要看一下 StandardServer 重要的一個方法 addService 的實現(xiàn):
2) StandardServer.addService
public void addService(Service service) {
service.setServer(this);
synchronized (services) {
Service results[] = new Service[services.length + 1];
System.arraycopy(services, 0, results, 0, services.length);
results[services.length] = service;
services = results;
if (initialized) {
try {
service.initialize();
} catch (LifecycleException e) {
e.printStackTrace(System.err);
}
}
if (started && (service instanceof Lifecycle)) {
try {
((Lifecycle) service).start();
} catch (LifecycleException e) {
;
}
}
support.firePropertyChange("service", null, service);
}
}
從上面第一句就知道了 Service 和 Server 是相互關聯(lián)的,Server也是和 Service 管理 Connector 一樣管理它,也是將 Service 放在一個數(shù)組中,后面部分的代碼也是管理這個新加進來的 Service 的生命周期。Tomcat6 中也是沒有什么變化的。
組件的生命線“Lifecycle”
前面一直在說 Service 和 Server 管理它下面組件的生命周期,那它們是如何管理的呢?
Tomcat 中組件的生命周期是通過 Lifecycle 接口來控制的,組件只要繼承這個接口并實現(xiàn)其中的方法就可以統(tǒng)一被擁有它的組件控制了,這樣一層一層的直到一個最高級的組件就可以控制 Tomcat 中所有組件的生命周期,這個最高的組件就是 Server,而控制 Server 的是 Startup,也就是您啟動和關閉 Tomcat。
下面是 Lifecycle 接口的類結構圖:
1) Lifecycle 類結構圖
除了控制生命周期的 Start 和 Stop 方法外還有一個監(jiān)聽機制,在生命周期開始和結束的時候做一些額外的操作。這個機制在其它的框架中也被使用,如在 Spring 中。關于這個設計模式會在后面介紹。
Lifecycle 接口的方法的實現(xiàn)都在其它組件中,就像前面中說的,組件的生命周期由包含它的父組件控制,所以它的 Start 方法自然就是調(diào)用它下面的組件的 Start 方法,Stop 方法也是一樣。如在 Server 中 Start 方法就會調(diào)用 Service 組件的 Start 方法,Server 的Start 方法代碼如下:
2) StandardServer.Start
public void start() throws LifecycleException {
if (started) {
log.debug(sm.getString("standardServer.start.started"));
return;
}
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
synchronized (services) {
for (int i = 0; i < services.length; i++) {
if (services[i] instanceof Lifecycle)
((Lifecycle) services[i]).start();
}
}
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
監(jiān)聽的代碼會包圍 Service 組件的啟動過程,就是簡單的循環(huán)啟動所有 Service 組件的Start方法,但是所有 Service 必須要實現(xiàn)Lifecycle 接口,這樣做會更加靈活。
Server 的 Stop 方法代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-820217.html
3) StandardServer.Stop
public void stop() throws LifecycleException {
if (!started)
return;
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
for (int i = 0; i < services.length; i++) {
if (services[i] instanceof Lifecycle)
((Lifecycle) services[i]).stop();
}
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
它所要做的事情也和 Start 方法差不多。文章來源地址http://www.zghlxwxcb.cn/news/detail-820217.html
到了這里,關于【分布式技術專題】「分布式技術架構」 探索Tomcat技術架構設計模式的奧秘(Server和Service組件原理分析)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!