Tomcat是帮助程序员快速建立web应用的助手。
从servlet到Spring MVC 到SpringBoot。tomcat一直离不开。现在虽然嵌入了SpringBoot但是依然需要了解tomcat的使用原理以及改进趋势。
Tomcat的定位是web服务器(servlet容器)。同样类型的还有:Resin,Jetty,WebLogic以及JBoss
为什么现在基本都是tomcat呢?先看两个概念
Web容器
给处于其中的应用程序组件(JSP、Servlet)提供一个环境,使得JSP,Servlet能直接和容器中的环境变量、接口交互而不必关注其他系统问题。主要是由Web服务器来实现,例如Tomcat、WebLogic和Websphere等。该容器提供的接口严格遵守J2EE规范中的Web Application标准。我们把遵守以上标准的Web服务器就叫做J2EE中的Web容器。
EJB(Enterprise Java Bean)容器
企业级Java Bean容器。更具有行业领域特色。他提供给运行在其中的EJB组件各种管理功能。只要满足J2EE规范的EJB放入该容器中,马上就会被容器进行高效率的管理。并且可以通过现成的接口来获得系统级别的服务,例如邮件服务和事务管理等。Web容器和EJB容器在原理上是大体相同的,更多的区别是被隔离的外界环境。Web容器更多的是和基于HTTP的请求打交道。而EJB容器不是,它更多的是和数据库和其他服务打交道。但是它们都是把与外界的交互实现,从而减轻应用程序的负担。例如Servlet不用关心HTTP的细节,直接引用环境变量session、request和response就行;EJB不用关心数据库连接速度、各种事务控制,都直接交给容器来完成。
在Tomcat的官网:Apache Tomcat软件是Java Servlet、Java服务器页面、Java表达式语言和Java WebSocket技术的开源实现。有这样的一个介绍。
找了一个Tomcat的架构图, 一个Connecter将在某个指定的端口上侦听客户请求,接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理Engine(Container中的一部分),从Engine出获得响应并返回客户。
Tomcat中有两个经典的Connector,一个直接侦听来自Browser的HTTP请求,另外一个来自其他的WebServer请求。HTTP/1.1 Connector在端口8080处侦听来自客户Browser的HTTP请求,AJP/1.3 Connector在端口8009处侦听其他Web Server(其他的HTTP服务器)的Servlet/JSP请求。
Connector 最重要的功能就是接收连接请求然后分配线程让 Container 来处理这个请求,所以这必然是多线程的,多线程的处理是 Connector 设计的核心。
Connector 类本身的作用主要是在其创建时创建ProtocolHandler,然后在生命周期的相关方法中调用了ProtocolHandler 的相关生命周期方法。Connector 的使用方法是通过Connector 标签配置在conf/server.xml 文件中,所以Connector 是在Catalina 的load 方法中根据conf/server.xml 配置文件创建Server对象时创建的。Connector 的生命周期方法是在Service 中调用的。
Connector 的创建过程主要是初始化ProtocolHandler。server.xrnl 配置文件中Connector 标签的protocol 属性会设置到Connector 构造函数的参数中,它用于指定ProtocolHandler 的类型
public Connector(String protocol) { setProtocol(protocol); // Instantiate protocol handler try { Class<?> clazz = Class.forName(protocolHandlerClassName); this.protocolHandler = (ProtocolHandler) clazz.newInstance(); } catch (Exception e) { log.error(sm.getString( "coyoteConnector.protocolHandlerInstantiationFailed"), e); } }
setProtocol方法
/** * Set the Coyote protocol which will be used by the connector. * * @param protocol The Coyote protocol name */ public void setProtocol(String protocol) { if (AprLifecycleListener.isAprAvailable()) { if ("HTTP/1.1".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.http11.Http11AprProtocol"); } else if ("AJP/1.3".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.ajp.AjpAprProtocol"); } else if (protocol != null) { setProtocolHandlerClassName(protocol); } else { setProtocolHandlerClassName ("org.apache.coyote.http11.Http11AprProtocol"); } } else { if ("HTTP/1.1".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.http11.Http11Protocol"); } else if ("AJP/1.3".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.ajp.AjpProtocol"); } else if (protocol != null) { setProtocolHandlerClassName(protocol); } } }
Apr 是Apache Portable Runtime 的缩写,是Apache 提供的一个运行时环境,如果要使用Apr 需要先安装,安装后Tomcat 可以自己检测出来。如果安装了Apr, setProtocol 方法会根据配置的HTTP/1.1 属性对应地将protocolHandlerClassName 设置为org.apache.coyote.http11.Http11.AprProtocol ,如果没有安装Apr,会根据配置的HTTP/1.1 属性将protocoHandlerClassName设置为com..apache.coyote.http11.Http11NioProtocol,然后就会根据protocolHandlerClassName 来创建ProtocolHandler。
协议处理器ProtocolHandler