启动应用程序
你可以从ex03.pyrmont.startup.Bootstrap类来启动应用程序。这个类在Listing 3.1中给出。Listing 3.1: Bootstrap类
package ex03.pyrmont.startup;Bootstrap类中的main方法实例化HttpConnector类并调用它的start方法。HttpConnector类在Listing 3.2给出。
import ex03.pyrmont.connector.http.HttpConnector;
public final class Bootstrap {
public static void main(String[] args) {
HttpConnector connector = new HttpConnector();
connector.start();
}
}
Listing 3.2: HttpConnector类的start方法
package ex03.pyrmont.connector.http;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpConnector implements Runnable {
boolean stopped;
private String scheme = "http";
public String getScheme() {
return scheme;
}
public void run() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new
ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
}
catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while (!stopped) {
// Accept the next incoming connection from the server socket
Socket socket = null;
try {
socket = serverSocket.accept();
}
catch (Exception e) {
continue;
}
// Hand this socket off to an HttpProcessor
HttpProcessor processor = new HttpProcessor(this);
processor.process(socket);
}
}
public void start() {
Thread thread = new Thread(this);
thread.start ();
}
}
连接器
ex03.pyrmont.connector.http.HttpConnector类指代一个连接器,职责是创建一个服务器套接字用来等待前来的HTTP请求。这个类在Listing 3.2中出现。
HttpConnector类实现了java.lang.Runnable,所以它能被它自己的线程专用。当你启动应用程序,一个HttpConnector的实例被创建,并且它的run方法被执行。
注意: 你可以通过读"Working with Threads"这篇文章来提醒你自己怎样创建Java线程。
run方法包括一个while循环,用来做下面的事情:
注意:run方法类似于第2章中HttpServer1类的await方法。
- 等待HTTP请求
- 为每个请求创建个HttpProcessor实例
- 调用HttpProcessor的process方法
马上你就会看到HttpConnector类和ex02.pyrmont.HttpServer1类非常相像,除了从 java.net.ServerSocket类的accept方法中获得一个套接字之后,一个HttpProcessor实例会被创建,并且通过传递该套 接字给它的process方法调用。
注意:HttpConnector类有另一个方法叫getScheme,用来返回一个scheme(HTTP)。
HttpProcessor类的process方法接受前来的HTTP请求的套接字,会做下面的事情:
1. 创建一个HttpRequest对象。
2. 创建一个HttpResponse对象。
3. 解析HTTP请求的第一行和头部,并放到HttpRequest对象。
4. 解析HttpRequest和HttpResponse对象到一个ServletProcessor或者 StaticResourceProcessor。像第2章里边说的,ServletProcessor调用被请求的servlet的service方 法,而StaticResourceProcessor发送一个静态资源的内容。
process方法在Listing 3.3给出.
Listing 3.3: HttpProcessor类process方法
public void process(Socket socket) {process首先获得套接字的输入流和输出流。请注意,在这个方法中,我们适合继承了java.io.InputStream的SocketInputStream类。
SocketInputStream input = null;
OutputStream output = null;
try {
input = new SocketInputStream(socket.getInputStream(), 2048);
output = socket.getOutputStream();
// create HttpRequest object and parse
request = new HttpRequest(input);
// create HttpResponse object
response = new HttpResponse(output);
response.setRequest(request);
response.setHeader("Server", "Pyrmont Servlet Container");
parseRequest(input, output);
parseHeaders(input);
//check if this is a request for a servlet or a static resource
//a request for a servlet begins with "/servlet/"
if (request.getRequestURI().startsWith("/servlet/")) {
ServletProcessor processor = new ServletProcessor();
processor.process(request, response);
}
else {
StaticResourceProcessor processor = new
StaticResourceProcessor();
processor.process(request, response);
}
// Close the socket
socket.close();
// no shutdown for this application
}
catch (Exception e) {
e.printStackTrace ();
}
}
SocketInputStream input = null;然后,它创建一个HttpRequest实例和一个 instance and an HttpResponse instance and assigns
OutputStream output = null;
try {
input = new SocketInputStream(socket.getInputStream(), 2048);
output = socket.getOutputStream();
the HttpRequest to the HttpResponse.
// create HttpRequest object and parse本章应用程序的HttpResponse类要比第2章中的Response类复杂得多。举例来说,你可以通过调用他的setHeader方法来发送头部到一个客户端。
request = new HttpRequest(input);
// create HttpResponse object
response = new HttpResponse(output);
response.setRequest(request);
response.setHeader("Server", "Pyrmont Servlet Container");接下去,process方法调用HttpProcessor类中的两个私有方法来解析请求。
parseRequest(input, output);然后,它根据请求URI的形式把HttpRequest和HttpResponse对象传给ServletProcessor或者StaticResourceProcessor进行处理。
parseHeaders (input);
if (request.getRequestURI().startsWith("/servlet/")) {最后,它关闭套接字。
ServletProcessor processor = new ServletProcessor();
processor.process(request, response);
}
else {
StaticResourceProcessor processor =
new StaticResourceProcessor();
processor.process(request, response);
}
socket.close();也要注意的是,HttpProcessor类使用org.apache.catalina.util.StringManager类来发送错误信息:
protected StringManager sm =HttpProcessor类中的私有方法--parseRequest,parseHeaders和normalize,是用来帮助填充HttpRequest的。这些方法将会在下节"创建一个HttpRequest对象"中进行讨论。
StringManager.getManager("ex03.pyrmont.connector.http");