Tomcat原始碼閱讀筆記

leyan發表於2018-01-29

概況:

Tomcat 的總體結構圖

Tomcat 的總體結構圖
作為大天朝子民的我們不難發現圖中Tomcat的兩個核心元件:ConnectorContainer

Connector Container
負責和外界取得聯絡,即建立連線(一個Connetor元件只能處理一種請求協議,例如一個Connector元件不能既處理http方式的請求又能處理https請求,因此需要多個Connector元件。) 負責處理Connector接受的請求,主要是處理內部事務(Container包含了Engine,Host,Context,Wrapper四個元件,負責處理請求相關的邏輯)

Service 只是在 Connector 和 Container 外面多包一層,把它們組裝在一起,對外提供服務,一個 Service 可以設定多個 Connector,但是隻能有一個 Container 容器。 Server控制Tomcat的整個生命週期。


認識 StandardService:

Service介面 Lifecycle介面
關聯Connector和Container,同時初始化它下面的其他元件 控制所有元件的生命週期

StandardService實現了Service介面和Lifecycle介面,這樣它就可以控制它下面元件的生命週期了;除了對Service和Lifecycle介面方法的實現它還有幾個方法是用於事件監聽方法的實現。

圖 Service 介面

圖 Service 介面
圖 StandardService 類
圖 StandardService 類

原始碼剖析
下面看一下 StandardService 中主要的幾個方法實現的程式碼,下面是 setContaineraddConnector 方法的原始碼:
清單 1. 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 有沒有已經關聯了 Container,如果已經關聯了,那麼去掉這個關聯關係—— oldContainer.setService(null)。如果這個 oldContainer 已經被啟動了,結束它的生命週期。然後再替換新的關聯、再初始化並開始這個新的 Container 的生命週期。最後將這個過程通知感興趣的事件監聽程式。
清單 2. 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 方法,這個方法也很簡單,首先是設定關聯關係,然後是初始化工作,開始新的生命週期。

注意: Connector 用的是陣列而不是 List 集合,這個從效能角度考慮可以理解,有趣的是這裡用了陣列但是並沒有向我們平常那樣,一開始就分配一個固定大小的陣列,它這裡的實現機制是:重新建立一個當前大小的陣列物件,然後將原來的陣列物件 copy 到新的陣列中,這種方式實現了類似的動態陣列的功能,這種實現方式,值得我們以後拿來借鑑。


認識StandardServer

Server 的任務:就是要能夠提供一個介面讓其它程式能夠訪問到這個 Service 集合、同時要維護它所包含的所有 Service 的生命週期,包括如何初始化、如何結束服務、如何找到別人要訪問的 Service。

Server 類結構圖

Server 類結構圖

它的標準實現類 StandardServer 實現了上面這些方法,同時也實現了 Lifecycle、MbeanRegistration 兩個介面的所有方法,下面主要看一下 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 是相互關聯的,Server 也是和 Service 管理 Connector 一樣管理它,也是將 Service 放在一個陣列中,後面部分的程式碼也是管理這個新加進來的 Service 的生命週期。Tomcat6 中也是沒有什麼變化的。

相關文章