servlet解析演进(1)

写程序的人,尤其是写web程序的人都不会对servlet感到陌生。在我们实现自己servlet的时候只要在web页面配置下servlet信息,并且实现servlet的service方法就完事儿大吉了。

简单的实现servlet解析至少需要实现连接器、处理器。连接器负责打开连接门户socket。处理器负责创建数据处理对象,解析http请求。

1、连接器职责:

ServerSocket serverSocket = null;
int port = 8080;
try {//生成服务器socket
  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
    socket = serverSocket.accept();
  }
  catch (Exception e) {
    continue;
  }
  //调用处理器处理请求
  HttpProcessor processor = new HttpProcessor(this);
  processor.process(socket);
}

2、处理器的职责

2.1、创建HttpRequest、HttpResponse

//通过socket的输入流生成输入流缓冲区
 input = new SocketInputStream(socket.getInputStream(), 2048);
//创建socket输出流缓冲区
 output = socket.getOutputStream();
 // 创建HttpRequest实例
 request = new HttpRequest(input);
 // 创建HttpResponse实例对象
 response = new HttpResponse(output);
 response.setRequest(request);
 response.setHeader("Server", "Pyrmont Servlet Container");

2.2、解析请求行 parseRequest(input, output);

// 解析请求行
  input.readRequestLine(requestLine);
  //获得方法名称 post/get
  String method =
    new String(requestLine.method, 0, requestLine.methodEnd);
  String uri = null;
  //获得协议名称http/1.1
  String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd);
  // Validate the incoming request line
  if (method.length() < 1) {
    throw new ServletException("Missing HTTP request method");
  }
  else if (requestLine.uriEnd < 1) {
    throw new ServletException("Missing HTTP request URI");
  }
  // Parse any query parameters out of the request URI
  //解析uri以外的参数
  int question = requestLine.indexOf("?");
  if (question >= 0) {
    request.setQueryString(new String(requestLine.uri, question + 1,
      requestLine.uriEnd - question - 1));
    uri = new String(requestLine.uri, 0, question);
  }
  else {
    request.setQueryString(null);
    uri = new String(requestLine.uri, 0, requestLine.uriEnd);
  }
  //获取uri的绝对路径,将http://等信息跳过去
  if (!uri.startsWith("/")) {
    int pos = uri.indexOf("://");
    // Parsing out protocol and host name
    if (pos != -1) {
      pos = uri.indexOf('/', pos + 3);
      if (pos == -1) {
        uri = "";
      }
      else {
        uri = uri.substring(pos);
      }
    }
  }
  // uri之外的jessionid信息,如果有设置到request的sessionId之中
  String match = ";jsessionid=";
  int semicolon = uri.indexOf(match);
  if (semicolon >= 0) {
    String rest = uri.substring(semicolon + match.length());
    //该行除了jessionid之外还有别的字符串
    int semicolon2 = rest.indexOf(';');
    if (semicolon2 >= 0) {
      request.setRequestedSessionId(rest.substring(0, semicolon2));
      rest = rest.substring(semicolon2);
    }
    else {
      //只有jessionid信息,直接设置其到requestedSessionId字段中
      request.setRequestedSessionId(rest);
      rest = "";
    }
    request.setRequestedSessionURL(true);
    uri = uri.substring(0, semicolon) + rest;
  }
  else {
    //如果没有jsessionid,则对应字段置空
    request.setRequestedSessionId(null);
    request.setRequestedSessionURL(false);
  }
  // Normalize URI (using String operations at the moment)
  String normalizedUri = normalize(uri);
  // 设置方法和协议
  ((HttpRequest) request).setMethod(method);
  request.setProtocol(protocol);
  if (normalizedUri != null) {
    ((HttpRequest) request).setRequestURI(normalizedUri);
  }
  else {
    ((HttpRequest) request).setRequestURI(uri);
  }
  if (normalizedUri == null) {
    throw new ServletException("Invalid URI: " + uri + "'");
  }
}

2.3、解析请求头   parseHeaders(input)

while (true) {
  HttpHeader header = new HttpHeader();;
  // 按行解析请求行
  input.readHeader(header);
  if (header.nameEnd == 0) {
    if (header.valueEnd == 0) {
      return;
    }
    else {
      throw new ServletException
        (sm.getString("httpProcessor.parseHeaders.colon"));
    }
  }
  String name = new String(header.name, 0, header.nameEnd);
  String value = new String(header.value, 0, header.valueEnd);
  // 设置httprequest 头字段
  request.addHeader(name, value);
 //设置cookie字段
  if (name.equals("cookie")) {
    Cookie cookies[] = RequestUtil.parseCookieHeader(value);
    for (int i = 0; i < cookies.length; i++) {
      if (cookies[i].getName().equals("jsessionid")) {
        // Override anything requested in the URL
        if (!request.isRequestedSessionIdFromCookie()) {
          // Accept only the first session id cookie
          request.setRequestedSessionId(cookies[i].getValue());
          request.setRequestedSessionCookie(true);
          request.setRequestedSessionURL(false);
        }
      }
      request.addCookie(cookies[i]);
    }
  }
  //设置contentLength字段
  else if (name.equals("content-length")) {
    int n = -1;
    try {
      n = Integer.parseInt(value);
    }
    catch (Exception e) {
      throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength"));
    }
    request.setContentLength(n);
  }
  //设置contentType字段
  else if (name.equals("content-type")) {
    request.setContentType(value);
  }
} //end while


2.4、servlet创建,并执行service方法。

public void process(HttpRequest request, HttpResponse response) {
  String uri = request.getRequestURI();
  String servletName = uri.substring(uri.lastIndexOf("/") + 1);
  URLClassLoader loader = null;
  try {
    // 创建类加载器 URLClassLoader
    URL[] urls = new URL[1];
    URLStreamHandler streamHandler = null;
    //获取类路径
    File classPath = new File(Constants.WEB_ROOT);
    String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
    urls[0] = new URL(null, repository, streamHandler);
    loader = new URLClassLoader(urls);
  }
  catch (IOException e) {
    System.out.println(e.toString() );
  }
  Class myClass = null;
  try {
    //类路径中加载类
    myClass = loader.loadClass(servletName);
  }
  catch (ClassNotFoundException e) {
    System.out.println(e.toString());
  }
  Servlet servlet = null;
  try {
    //实例化类
    servlet = (Servlet) myClass.newInstance();
    //创建request门面模式
    HttpRequestFacade requestFacade = new HttpRequestFacade(request);
    //创建response门面模式
    HttpResponseFacade responseFacade = new HttpResponseFacade(response);
   //调用实例的service方法
    servlet.service(requestFacade, responseFacade);
    //servlet执行完毕,调用fresh方法将数据写入输出流中
    ((HttpResponse) response).finishResponse();
  }
  catch (Exception e) {
    System.out.println(e.toString());
  }
  catch (Throwable e) {
    System.out.println(e.toString());
  }
}


题外话:

Facate设计模式:

有的时候不想暴露一些方法,可以通过门面模式去实现。

类A有方法B不想暴漏。类A实现了接口C。 那么生成类D,让其实现接口C。并将接口C放置到类D中去。这样,在调用类A的时候,我们可以将其包装成门面模式去暴露给外部接口使用。这样即能够暴露需要暴露的方法,又能够不暴露不需要暴露的方法。

在tomcat实现httpRequest的时候,使用了门面模式。也就是说暴露给我们自定义servlet的不是httpRequest实例,而是httpRequest的门面类实例。原因就是上面说的。


你可能感兴趣的:(servlet解析演进(1))