美文网首页
How Tomcat Works读书笔记

How Tomcat Works读书笔记

作者: yang2yang | 来源:发表于2016-09-25 22:31 被阅读1150次

首先明确Tomcat的职责是什么,也就是说Tomcat做了哪些事情?
我觉得下面几件事情是Tomcat必须要做的比较重要的事情。

  1. 监听某个端口,捕获HTTP请求。
  2. 将HTTP请求转换为相应的Request对象,当然也应该需要创建一个Response对象
  3. 然后初始化一个Servlet对象,或者说加载一个Servlet对象,将相应的Request对象和Response对象传递进去,之后调用Servlet中的service函数。

Tomcat的架构图

Tomcat的架构图.png

上面一张图片比较详细,下面放一张简单一点的架构图。

imgr.jpg

Tomcat的架构浅析

通过图片可以看到Tomcat是分成好几个模块的。最外面是一个Server,一个Server可以有好几个Service服务,一个Service服务会有几个Connector组件,但是只会有一个Container组件,另外还有好几个不是那么核心的组件,比如说管理Session的组件,写日志的组件。

其中也提到了最核心的组件(Component)就是ConnectorContainer

Connector的作用就是监听某一个端口,然后接受HTTP请求,将HTTP请求封装成Servlet需要使用的HttpServletRequest对象和HttpServletResponse对象。也就是说将纯文本的Http请求解析出来了之后变成可以方便使用的Request对象,而Response对象需要作为一个返回值的容纳地,也是需要传递给Servlet*的。

Container的作用就是根据Request中URL中的信息加载相应的Servlet对象,之后就是调用相应的方法,讲结果封装在Response对象中,最后当然也是转换为HTTP的文本返回给客户端。

A Simple Servlet Container

当有了基本的架构概念了之后,我觉得可以直接看一些简单的小例子,来看一下在代码中这些组件是如何关联作用在一起的,下面就把How Tomcat Works中的一个第五章中的小例子贴出来。(其实前面几个章节有更加简单的例子,感兴趣的可以看下。)

package ex05.pyrmont.startup;

import ex05.pyrmont.core.SimpleContext;
import ex05.pyrmont.core.SimpleContextMapper;
import ex05.pyrmont.core.SimpleLoader;
import ex05.pyrmont.core.SimpleWrapper;
import ex05.pyrmont.valves.ClientIPLoggerValve;
import ex05.pyrmont.valves.HeaderLoggerValve;
import org.apache.catalina.Context;
import org.apache.catalina.Loader;
import org.apache.catalina.Mapper;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.http.HttpConnector;

public final class Bootstrap2 {
  public static void main(String[] args) {
    HttpConnector connector = new HttpConnector();
    //继承了Wrapper,每一个实例里面都是会有一个Servlet的
    Wrapper wrapper1 = new SimpleWrapper();
    //设置Servlet的映射地址
    wrapper1.setName("Primitive");
   //设置Servlet的名字
    wrapper1.setServletClass("PrimitiveServlet");
    Wrapper wrapper2 = new SimpleWrapper();
    wrapper2.setName("Modern");
    wrapper2.setServletClass("ModernServlet");
 
    //context是一个容器可以包含wrapper这个最底层的容器
    Context context = new SimpleContext();
    context.addChild(wrapper1);
    context.addChild(wrapper2);

    Valve valve1 = new HeaderLoggerValve();
    Valve valve2 = new ClientIPLoggerValve();
    //容器中除了其他容器之外还有Valve
    //另外要注意的是每一个context都是实现了Pipeline和Context接口的
    ((Pipeline) context).addValve(valve1);
    ((Pipeline) context).addValve(valve2);
    //这个mapper是做什么的呢?
    Mapper mapper = new SimpleContextMapper();
    mapper.setProtocol("http");
    context.addMapper(mapper);
    Loader loader = new SimpleLoader();
    //容器中还需要加载器,通过反射加载真正的Servlet对象
     context.setLoader(loader);
    // context.addServletMapping(pattern, name);
   //context里面初始化了一个HashMap,存储映射和Servlet名字
    context.addServletMapping("/Primitive", "Primitive");
    context.addServletMapping("/Modern", "Modern");
    //因为connector封装好Reqeust之后会调用容器,所以将容器的声明给Connector
    connector.setContainer(context);
    try {
      connector.initialize();
       //connector开始监听端口,要明白底层肯定使用ServerSocket来实现的
      connector.start();

      // make the application wait until we press a key.
      System.in.read();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}

BootStrap是一个Tomcat启动的程序入口。可以看到源代码中初始化了这么几个对象,一个HttpConnector,两个Wrapper,一个Context,两个Valve,一个Loader等,具体可以看注释,还是把我的理解写在注释里面把。

再看一张图

host_context_wrapper之间的关系.jpg

从第一张架构图中可以看到container是分成下面几个容器的,engine,host,context,wrapper。关系是这样的一个engine是可以有零个或者多个host的,以此类推。

那么这些容器的作用是什么呢?其实是用来匹配相应的URL,也就是讲一个请求的URL来分成者三个部分,最后找到要请求的Servlet。也就是说request是不断地在容器中传递的。其实容器中还有一个叫做Pipeline的东西,暂时还是不是很明白这个东西的作用是什么,每一个Pipeline都有很多的Valve。(有一点是这样的,Pipeline其实和过滤器是一个很像的东西)

ServletContext在哪里呢?

其实就是StandardContext中的一个全局变量。
Tomcat8.0.37中StandardContext.java部分源码

public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter
    /**
     * The ServletContext implementation associated with this Context.
     */
    protected ApplicationContext context = null;
    /**
     * Return the servlet context for which this Context is a facade.
     */
    @Override
    public ServletContext getServletContext() {

        if (context == null) {
            context = new ApplicationContext(this);
            if (altDDName != null)
                context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
        }
        return (context.getFacade());

    }

最后

其实现在如果是用Springmvc这个框架的话,其实只是在web.xml中配置了一个拦截所有请求的前端Servlet,但是之后的事情比如Controller之类的东西都是Sringmvc在做了,而不是最原始的一个请求对应一个Servlet了。

最后的最后

因个人能力有限,以上内容肯定会有错误,所有欢迎交流讨论,另外如果觉得有帮助,可以点击一个喜欢,将这篇文章献给以后的自己和看到最后的你。

参考

JavaWeb学习之Servlet(四)----ServletConfig获取配置信息、ServletContext的应用

Tomcat容器结构及Pipeline机制 -我们到底能走多远系列(13)
tomcat架构分析概览
粗浅看 Tomcat系统架构分析
How do servlets work? Instantiation, sessions, shared variables and multithreading
Tomcat源码分析之容器整体结构

相关文章

网友评论

      本文标题:How Tomcat Works读书笔记

      本文链接:https://www.haomeiwen.com/subject/cypfyttx.html