几个概念

HttpServlet,Servlet

Servlet是一个接口,定义了一种网络服务,我们所有的servlet都要实现它(或它的子类)

HttpServlet是一个抽象类,它针对的就是http网络服务

当然如果以后再有其他的网络服务,可以再定义一个类,让它实现Servlet即可。

HttpServletRequest,ServletRequest

先说ServletRequest接口,它用来传递网络服务的请求,用在Servlet类的service方法。

那么HttpServletRequest接口,主要针对的就是http请求。

HttpServletRequest比ServletRequest多了一些针对于Http协议的方法。如getHeader,getMethod,getSession等。

StringManager

对于一个大型的系统,任何时候都要小心的处理错误信息。如果将所有的错误信息都保存在一个properties文件中,会无比繁杂,因此tomcat为系统里面的每一个包都建立一组properties文件(是一组 而不是一个 是为了支持多语言 LocalStrings.properties,LocalStrings_es.properties,LocalStrings_ja.properties就分别是英语 西班牙语 日语)





例如在ex03.pyrmont.connector.http包下的HttpProcessor类中 我们引用StringManager 如下

  protected StringManager sm =

    StringManager.getManager("ex03.pyrmont.connector.http");

 在要抛出异常的地方使用

 throw new ServletException

            (sm.getString("httpProcessor.parseHeaders.colon"));

现在我们看看httpProcessor.parseHeaders.colon包下的properties文件(部分)

httpProcessor.parseHeaders.colon=Invalid HTTP header format

httpProcessor.starting=Starting background thread

httpProcessor.stopping=Stopping background thread

requestStream.close.closed=Request stream has already been closed

这下知道StringManager的功能了吧。

另外,StringManager的产生是单例模式,大家可以看看源码

lozy load

在本章,http请求对象使用httprequst来表示(jdk中并不存在这个类 我们自己写的),它实现了HttpServletRequest接口。

在使用的时候httprequst会被转型成HttpServletRequest,并作为servlet的service方法的参数而调用。

所以我们得设置每个httprequest实例的成员变量供servlet实例使用,需要设定的值包括uri,查询字符串,参数,Cookie等等

因而,这里就存在一个问题,解析http的请求体(注意是请求体 请求方法get/post那一行和请求头会全部解析)涉及很多字符串操作,如果我们只解析会用到的值就能节省很多cpu周期。

因此只有当我们调用javax.servlet.http.HttpServletRequest的getParameter(),getParameterMap(),getParameter-Names(),getParameterValues()时才会解析请求体(并且即使多次调用那个四个方法 也只解析一次)!

具体做法就是在HttpRequest类(我们自己写的那个实现了HttpServletRequest接口的那个)里上述四个方法里面第一行代码就调用一个parseParameters()方法。parsed的作用就是保证parseParameters只运行一次

(另外我觉得请求字符串应该就是请求体的一部分)



第二章帮我们建立了一个简单的servlet容器,它可以加载静态资源,还可以处理一些简单的servlet。在这一章里,我们要进一步完善我们的容器,让它能取得request请求的一些参数。

因此我们这一节的servlet就会继承HttpServlet,传递的参数也会是HttpServletRequest。

应用代码

我们这一章的servlet代码如下

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

public class ModernServlet extends HttpServlet {

  public void init(ServletConfig config) {
    System.out.println("ModernServlet -- init");
  }

  public void doGet(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {

    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Modern Servlet</title>");
    out.println("</head>");
    out.println("<body>");

    out.println("<h2>Headers</h2");
    Enumeration headers = request.getHeaderNames();
    while (headers.hasMoreElements()) {
      String header = (String) headers.nextElement();
      out.println("<br>" + header + " : " + request.getHeader(header));
    }

    //省略部分request信息
    out.println("</body>");
    out.println("</html>");

  }
}

首先看看UML图

系统提炼出来了一个Bootstrap类,加载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();
  }
}

HttpConnector的run方法其实与书的第一章的HttpServer1类似,只是第一章中获得inputstream后,就让他生成request了,而在这里,我们创建了httpprocessor,并调用其process方法将serverSocket.accept()的socket传入。

HttpProcessor的process方法如下

public void process(Socket socket) {

	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();
    }
  }

看这个一行代码

input = new SocketInputStream(socket.getInputStream(), 2048);

SocketInputStream是一个实现了InputStream接口的包装类,我们之所以用SocketInputStream,就是为了用它的readRequestLine()方法readHeader方法。前者能读出request请求的请求方法,uri和请求协议,后者能读出请求头。

构建HttpRequest

parseRequest(input, output);

    parseHeaders(input);

这两个方法是process方法的核心,也可以说是整个第三章的核心。往简单的说,这两个方法干的事就是解析http请求填充HttpRequst对象,当然这里面有很多很多细节的东西。

这部分说简单很简单,说麻烦也巨麻烦,大体来说就是五个部分

1读取套接字的输入流

 就是下面这行代码

  input = new SocketInputStream(socket.getInputStream(), 2048);

 大家有兴趣可以看看readRequestLine的源代码,不过不必深究。

2解析请求行(就是 http请求的第一行 包括请求方法 uri 协议版本)

3解析请求头

4解析Cookie

5获取参数(就是前文提到的lazy load)

构建HttpResponse


在第二章的ServletResponse中,我们只实现了部分功能,print方法不能自动刷新。

  public PrintWriter getWriter() throws IOException {
    // autoflush is true, println() will flush,
    // but print() will not.
    writer = new PrintWriter(output, true);
    return writer;
  }

通过上面第二章的代码,我们知道writer是一个PrintWriter类的实例。

1 在本章,我们使用ResponseWriter来构建writer实例(ResponseWriter继承自PrintWriter)

2 第二章的output是OutputStream接口的实例,在第三章,我们换成ResponseStream(ResponseStream 继承 ServletOutputStream,而后者又实现了OutputStream接口)

3 同时还需要一个OutputStreamWriter作为ResponseWriter与ResponseStream之间的桥梁。

所以代码如下

public PrintWriter getWriter() throws IOException {
    ResponseStream newStream = new ResponseStream(this);       // this 指代HttpResopnse
    newStream.setCommit(false);
    OutputStreamWriter osr =
      new OutputStreamWriter(newStream, getCharacterEncoding());
    writer = new ResponseWriter(osr);
    return writer;
  }

静态资源处理器与servlet处理器与上一章的内容基本一致,不再赘述。





参考资料

http://zhidao.baidu.com/link?url=BGdS8iiz12FmAlVLsoGj6n3LwclvQ7rD-8GOJ6U8uguM8IGZrDUooTkjnySAInrMkqA6a7XofgNu4J3ynbOPC_

How Tomcat Works读书笔记三-------连接器的更多相关文章

  1. how tomcat works 读书笔记(二)----------一个简单的servlet容器

    app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...

  2. how tomcat works 读书笔记四 tomcat的默认连接器

    事实上在第三章,就已经有了连接器的样子了,只是那仅仅是一个学习工具,在这一章我们会開始分析tomcat4里面的默认连接器. 连接器 Tomcat连接器必须满足下面几个要求 1 实现org.apache ...

  3. How tomcat works 读书笔记十四 服务器组件和服务组件

    之前的项目还是有些问题的,例如 1 只能有一个连接器,只能处理http请求,无法添加另外一个连接器用来处理https. 2 对容器的关闭只能是粗暴的关闭Bootstrap. 服务器组件 org.apa ...

  4. how tomcat works 读书笔记 十一 StandWrapper 上

    方法调用序列 下图展示了方法调用的协作图:  这个是前面第五章里,我画的图:  我们再回顾一下自从连接器里  connector.getContainer().invoke(request, resp ...

  5. how tomcat works 读书笔记(一)----------一个简单的webserver

    http协议 若是两个人能正常的说话交流,那么他们间必然有一套统一的语言规则<在网络上server与client能交流也依赖与一套规则,它就是我们说的http规则(超文本传输协议Hypertex ...

  6. how tomcat works 读书笔记九 Session管理

    在看本文之前,请先查阅相关Session与Cookie的资料. 这篇资料不错 http://blog.csdn.net/fangaoxin/article/details/6952954 Catali ...

  7. how tomcat works 读书笔记(一)----------一个简单的web服务器

    http协议 若是两个人能正常的说话交流,那么他们间必定有一套统一的语言规则<在网络上服务器与客户端能交流也依赖与一套规则,它就是我们说的http规则(超文本传输协议Hypertext tran ...

  8. How Tomcat Works 读书笔记 八 载入器 上

    Java的类载入器 详细资料见 http://blog.csdn.net/dlf123321/article/details/39957175 http://blog.csdn.net/dlf1233 ...

  9. How tomcat works 读书笔记十七 启动tomcat 上

    一路跋山涉水,这是最后一章了. 关于tomcat的启动,有两个类,一个是Catalina类,一个是Bootstrap类. 理论上,两个类可以和到一起,但是为了支持多种运行模式,又把他们分开了. 为了让 ...

随机推荐

  1. RxJava(一) create操作符的用法和源码分析

    欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/51524470 本文出自:[余志强的博客] 1 create操作符的基 ...

  2. 利用ScrollView滑动属性实现点击查看更多

    利用ScrollView的滚动实现点击查看更多 效果图 更新内容布局 <ScrollView android:id="@+id/sv_des" android:layout_ ...

  3. 如何将Provisioning Profile安装到开发的Mac系统上

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...

  4. iOS开发之Xcode8推出的WKWebView与UIWebView的使用

    一.整体介绍 UIWebView自iOS2就有,WKWebView从iOS8才有,毫无疑问WKWebView将逐步取代笨重的UIWebView.通过简单的测试即可发现UIWebView占用过多内存,且 ...

  5. cocos2d-x 3.11 游戏开发环境搭建流程

    cocos2d-x 3.11.1 游戏开发环境搭建流程 1. 准备下面的软件 1) Windows7 64Bit+ VS2013 (VC++) 这个不用多说. 2) cocos2d-x-3.11.1. ...

  6. hbase 程序优化 参数调整方法

    hbase读数据用scan,读数据加速的配置参数为: Scan scan = new Scan(); scan.setCaching(500); // 1 is the default in Scan ...

  7. [cacti]nginx+php+cacti+mysql+php-fpm 安装小记

    网上教程很多,但是nginx不太多,下面安装时候主要参考的篇文章: http://54im.com/linux/linux-cacti-cn-install.html http://www.tecmi ...

  8. 【一天一道LeetCode】#225. Implement Stack using Queues

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Impleme ...

  9. 安卓中的消息循环机制Handler及Looper详解

    我们知道安卓中的UI线程不是线程安全的,我们不能在UI线程中进行耗时操作,通常我们的做法是开启一个子线程在子线程中处理耗时操作,但是安卓规定不允许在子线程中进行UI的更新操作,通常我们会通过Handl ...

  10. Android的资源类型和存储方式简介-android学习之旅(五十二)

    android资源的类型 android资源的存储方式