之前的項目還是有些問題的,例如
1 隻能有一個連接配接器,隻能處理http請求,無法添加另外一個連接配接器用來處理https。
2 對容器的關閉隻能是粗暴的關閉Bootstrap。
伺服器元件
org.apache.catalina.Server接口的執行個體用來表示Catalina的整個servlet引擎。
我們使用Server就是因為,它用一種優雅的方式來啟動/關閉整個系統。
下面是啟動和停止機制是如何工作的。當伺服器啟動的時候,它啟動它内部的所有元件。然後無限期的等待關閉指令,如果你想要關閉系統,發送一個關閉指令道指定端口即可。當伺服器收到正确的關閉指令後,它停止所有元件的服務。
伺服器還使用了另外一個元件,即服務元件,它用來持有元件,例如容器或者一個多個的連接配接器。服務元件将在本章的 service 小節中介紹。(注意有伺服器元件,也有服務元件,這兩個是不一樣的。)
Server接口中屬性 shutdown 用來持有一個停止服務的指令。屬性 port 則是伺服器等待關閉指令的端口。可以調用伺服器的 addService 方法将服務添加到伺服器。使用removeService 方法将服務删除。findServices 傳回所有伺服器中所有的服務。
StandardServer類
StandardServer類是Server接口的标準實作。在這裡,我們主要介紹它的四個方法。initialize(),start(),stop(),await();
我們一個一個來說。
initialize方法
public void initialize() throws LifecycleException {
if (initialized)
throw new LifecycleException (
sm.getString("standardServer.initialize.initialized"));
initialized = true;
// Initialize our defined Services
for (int i = 0; i < services.length; i++) {
services[i].initialize();
}
}
我們能看到這裡使用了一個initialized來辨別伺服器是否已經初始化,同時初始化它所包含的服務元件。
另外在stop中,initialized并沒有更改,是以如果伺服器先初始化,再關閉,等再次初始化的時候會抛出異常。
start方法
public void start() throws LifecycleException {
// Validate and update our current component state
if (started)
throw new LifecycleException
(sm.getString("standardServer.start.started"));
// Notify our interested LifecycleListeners
...
started = true;
// Start our defined Services
synchronized (services) {
for (int i = 0; i < services.length; i++) {
if (services[i] instanceof Lifecycle)
((Lifecycle) services[i]).start();
}
}
// Notify our interested LifecycleListeners
...
}
和初始化幹的事情差不多,循環啟動它所關聯的服務元件。另外在stop方法中,started會被置為false。
stop方法
public void stop() throws LifecycleException {
// Validate and update our current component state
if (!started)
throw new LifecycleException
(sm.getString("standardServer.stop.notStarted"));
// Notify our interested LifecycleListeners
...
started = false;
// Stop our defined Services
for (int i = 0; i < services.length; i++) {
if (services[i] instanceof Lifecycle)
((Lifecycle) services[i]).stop();
}
// Notify our interested LifecycleListeners
...
}
關閉所有的服務元件。
await方法
這裡不再貼出代碼,await做的事就是監聽8005端口,如果使用者給8005端口發來"SHUTDOWN"就關閉serverSocket,然後await方法就執行完了。
現在再說說initialize方法,start方法,await方法,stop四者者都是在Bootstrap裡調用的。
當await方法執行完畢後,就會調用伺服器的stop方法。
Service接口
org.apache.catalina.Service 接口用于表示服務。一個服務可以有一個容器和多個連接配接器。你可以添加多個連接配接器 ,并将它們跟容器相關聯。
StandardService類
StandardService是Service接口的标準實作。
容器與連接配接器
一個 StandardService 執行個體包括兩種元件:一個容器和多個連接配接器。多個連接配接器可以使得 Tomcat 能服務于多個協定。一個協定用處處理 HTTP 請求,另一個用于處理 HTTPS 請求。
StandardService 類用 container 變量來持有容器執行個體,用 connectors 數組來持有所有的連接配接器
private Container container = null;
private Connector connectors[] = new Connector[0];
要将一個容器跟一個服務相關聯,可以使用它的 setContainer 方法,
在setContainer中,會把container傳遞給每一個connector。
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++)
connectors[i].setContainer(this.container);
}
要給一個服務添加連接配接器,可以使用 addConnector 方法。在添加連接配接器的同時也會初始化他們。
要删除一個連接配接器,可以使用 removeConnector 方法。
與生命周期相關的方法
這裡主要包含三個方法,initialize,start,stop。
initialize功能就是調用是以連接配接器的initialize方法。
start功能就是啟動容器和若幹個連接配接器。
stop功能就是關閉容器和若幹個連接配接器。
服務元件的這三個方法都會在伺服器元件裡相應的方法裡被調用,而伺服器元件的這三個方法是在Bootstrap裡調用的。
應用程式
這裡主要是兩個類,一個是 Bootstrap 啟動程式,另一個是 Stopper 類用來停止它。
Bootstrap類
public static void main(String args[]){
......
Service service = new StandardService();
service.setName("Stand-alone Service");
Server server = new StandardServer();
server.addService(service); //把服務元件添加到伺服器元件裡
service.addConnector(connector); //把連接配接器關聯到服務元件裡
//StandardService class's setContainer will call all its connector's setContainer method
service.setContainer(engine); //容器并沒有直接和連接配接器關聯,而是和服務元件關聯
// Start the new server
if (server instanceof Lifecycle) {
try {
server.initialize(); //調用initialize,start,await方法
((Lifecycle) server).start();//這裡會調用服務元件的start,來調用連接配接器與容器的start
//連接配接器會在8080上等待消息....
server.await(); //除非在8005端口收到了SHUTDOWN資訊 這裡會一直循環
// the program waits until the await method returns,
// i.e. until a shutdown command is received.
}
catch (LifecycleException e) {
e.printStackTrace(System.out);
}
}
// Shut down the server
if (server instanceof Lifecycle) {
try {
((Lifecycle) server).stop(); //收到了SHUTDOWM資訊,關閉伺服器元件
}
catch (LifecycleException e) {
e.printStackTrace(System.out);
}
}
}
Stopper類
public class Stopper {
public static void main(String[] args) {
// the following code is taken from the Stop method of
// the org.apache.catalina.startup.Catalina class
int port = 8005;
try {
Socket socket = new Socket("127.0.0.1", port);
OutputStream stream = socket.getOutputStream();
String shutdown = "SHUTDOWN";
for (int i = 0; i < shutdown.length(); i++)
stream.write(shutdown.charAt(i));
stream.flush();
stream.close();
socket.close();
System.out.println("The server was successfully shut down.");
}
catch (IOException e) {
System.out.println("Error. The server has not been started.");
}
}
}