Tomcat

2017/03/20 JavaEE

Tomcat

体系结构

体系结构

  • server
    • service
      • connector
      • engine
        • host
          • context
            • wrapper
              • servlet

启动过程

  • 初始化类加载器
  • 加载和配置的读取&解析
    • server.xml
  • 容器初始化
  • 容器启动

处理请求的过程和线程模型

  • BIO
    • 阻塞式IO,采用传统的java IO进行操作,该模式下每个请求都会创建一个线程,
    • 适用于并发量小的场景
    • Http11Protocol
  • NIO
    • 同步非阻塞,比传统BIO能更好的支持大并发,tomcat 8.0 后默认采用该模式
    • Http11NioProtocol
  • APR
    • tomcat 以JNI形式调用http服务器的核心动态链接库来处理文件读取或网络传输操作,需要编译安装APR库
    • Http11AprProtocol
  • AIO
    • 异步非阻塞,tomcat8.0后支持
    • Http11Nio2Protocol

Tomcat处理一个HTTP请求的过程

  1. 用户在浏览器中输入网址localhost:8080/test/index.jsp,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得;
  2. Connector把该请求交给它所在的Service的Engine(Container)来处理,并等待Engine的回应;
  3. Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host;
  4. Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理);
  5. path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL Pattern为*.jsp的Servlet,对应于JspServlet类;
  6. 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost(),执行业务逻辑、数据存储等;
  7. Context把执行完之后的HttpServletResponse对象返回给Host;
  8. Host把HttpServletResponse对象返回给Engine;
  9. Engine把HttpServletResponse对象返回Connector;
  10. Connector把HttpServletResponse对象返回给客户Browser。

一个典型的请求处理过程,其中绿色代表线程,蓝色代表数据:

一个典型的请求处理过程

Connector结构

Connector结构

  • Acceptor
    • 接收socket线程,这里虽然是基于NIO的connector,但是在接收socket方面还是传统的serverSocket.accept()方式,获得SocketChannel对象,然后封装在一个tomcat的实现类org.apache.tomcat.util.net.NioChannel对象中。
    • 然后将NioChannel对象封装在一个PollerEvent对象中,并将PollerEvent对象压入events queue里。
    • 这里是个典型的生产者-消费者模式,Acceptor与Poller线程之间通过queue通信,Acceptor是events queue的生产者,Poller是events queue的消费者。
  • Poller
    • Poller线程中维护了一个Selector对象,NIO就是基于Selector来完成逻辑的。
    • 在connector中并不止一个Selector,在socket的读写数据时,为了控制timeout也有一个Selector。可以先把Poller线程中维护的这个Selector标为主Selector。
    • Poller是NIO实现的主要线程。首先作为events queue的消费者,从queue中取出PollerEvent对象,然后将此对象中的channel以OP_READ事件注册到主Selector中,然后主Selector执行select操作,遍历出可以读数据的socket,并从Worker线程池中拿到可用的Worker线程,然后将socket传递给Worker。整个过程是典型的NIO实现。
  • Worker
    • Worker线程拿到Poller传过来的socket后,将socket封装在SocketProcessor对象中。
    • 然后从Http11ConnectionHandler中取出Http11NioProcessor对象,从Http11NioProcessor中调用CoyoteAdapter的逻辑,跟BIO实现一样。
    • 在Worker线程中,会完成从socket中读取http request,解析成HttpServletRequest对象,分派到相应的servlet并完成逻辑,然后将response通过socket发回client。
    • 再从socket中读数据和往socket中写数据的过程,并没有像典型的非阻塞的NIO的那样,注册OP_READ或OP_WRITE事件到主Selector,而是直接通过socket完成读写,这时是阻塞完成的,但是在timeout控制上,使用了NIO的Selector机制,但是这个Selector并不是Poller线程维护的主Selector,而是BlockPoller线程中维护的Selector,称之为辅Selector。

工作流程

工作流程

工作流程

虚似目录Context映射

在server.xml文件的host元素中配置

虚拟目录映射

在Tomcat6中,不再建议在server.xml文件中配置context元素,细节查看tomcat服务器关于context元素的说明。

  • <CATALINA_HOME>\conf\Catalina\localhost\文件夹下新建一个a.xml,配置<Context docBase="c:\news" />则映射到locahost:8080/a/
  • 新建ROOT.xml则映射根路径

Context常用属性

Context常用属性

session的持久化 钝化和活化

持久化解决服务器重启后session的恢复

实现的效果是这样的:

  1. 打开一个网页,网页的目的是输出session id;
  2. 关闭tomcat,则在temp文件夹(或者在work目录的app对应文件夹)下会出现一个临时文件;
  3. 重新启动tomcat,文件消失
  4. 刷新页面,session id不变;

钝化和活化可解决session过多占用内存高问题

  • 纯化:从内存中写到硬盘上(序列化)
  • 活化:从硬盘上读取到内存中(反序列化)

配置

  • <CATALINA_HOME>\conf\context.xml中可全局配置
<!-- 关闭session持久化 -->
<Manager pathname="" />
  • <CATALINA_HOME>\conf\server.xml中可针对应用进行配置
<Context path="/xpress" docBase="/data/tomcat/webapp" reloadable="true">  
    <Manager className="org.apache.catalina.session.PersistentManager">  
        debug=0     saveOnRestart="true"  
        maxActiveSession="-1"   minIdleSwap="-1"  
        maxIdleSwap="-1"        maxIdleBackup="-1"  
        <!-- 存储在文件系统 -->
        <Store className="org.apache.catalina.session.FileStore" directory="/data/tomcat/tomcatProject/temp"/>  
        <!-- 配置store节点存储在数据库 -->
        <Store calssName="org.apache.catalina.JDBCStore" driverName="com.mysql.jdbc.Driver"
			connectionURL="jdbc:mysql://localhost/session?usename=xxx&password=xxx"
			sessionTable="session" sessionIdCol="session_id" sessionDataCol="session_data"
			sessionValidCol="sessionValid" sessionMaxInactiveCol="maxInactive"
			sessionLastAccessedCol="lastAccess" sessionAppCol="appName" checkInterval="60" debug="99" />
    </Manager>  
</Context>  

manager标签配置详情


以上概念总结于传智播客Java基础课程

Search

    Post Directory