tomcat源码阅读-1

来源:互联网 发布:java对接微信公众平台 编辑:程序博客网 时间:2024/04/30 08:32

tomcat源码系列文章开始!!(不是为了说教,市面上讲tomcat的很多,我只是做笔记而已。。。)

虽然是tomcat源码系列的第一篇,但是其实是从第三章开始写的,原因嘛。。。因为我愿意这么写。。。


第三章源码分析:

主要类有以下几个:

1.启动类Bootstrap.class
2.连接器相关类HttpConnector.class和HttpProcessor.class
3.HTTP请求相关类HttpRequest.class,HttpResponse.class(以及两个facade类,主要是出于安全考虑,封装了组件内部的通信部分,只暴漏必要的部分)
4.请求处理类:静态资源处理类StaticResourceProcessor.class和动态资源处理类ServletProcessor.class

启动和处理请求流程如下:

1.首先Bootstrap启动类创建一个HttpConnector实例,该实例的类是一个实现了多线程接口的类,通过启动额外线程来监听相应地址和端口,并且阻塞等待请求到来:

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

以上代码通过一个while循环来接受请求,这几乎是所有web服务器的实现方式(在一个循环中阻塞等待请求),每次接收到一个请求都会创建一个HttpProcessor实例来处理请求,该类的职责就是解析http请求并且创建和填充HttpRequest和HttpResponse对象,注意这个时候只是把http请求解析到了Httprequest中,具体请求参数等步骤并没有做,而是等到具体servlet实例调用getParamter()等方法的时候才会去解析,这样的好处就是不做不必要的解析,在需要的时候再解析,减少了CPU等开销。代码如下:

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

静态处理器就不说了,这里再说一下动态(servlet)处理器部分的处理步骤:
1.首先通过解析url识别出请求的servlet名字
    String uri = request.getRequestURI();    String servletName = uri.substring(uri.lastIndexOf("/") + 1);

2.然后创建一个类加载器,并且加载请求的servlet

URLClassLoader loader = null;try {// create a URLClassLoaderURL[] 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());}


3.实例化servlet,调用service方法处理request(注意这里传入的是facade类)

      servlet = (Servlet) myClass.newInstance();      HttpRequestFacade requestFacade = new HttpRequestFacade(request);      HttpResponseFacade responseFacade = new HttpResponseFacade(response);      servlet.service(requestFacade, responseFacade);


4.最后返回结果,结束请求


这里再次提一下,只有在加载的servlet方法中调用了request.getParameters()等方法,才会解析请求内容,并且只会解析一次。
解析步骤可以在HttpRequest类中找到,是调用了 parseParameters()方法

ok,基本上一个请求流程就是这样了,另外HttpRequest类中的很多方法值得细看,特别是一些同步的部分


0 0