没有标准定义。一般认为,Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,提供网上信息浏览服务。
Tomcat是一款开源轻量级Web应用服务器,是一款优秀的Servlet容器实现。
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
Servlet严格来讲是指Java语言实现的一个接口,一般情况下我们说的Servlet是指任何实现了这个Servlet接口的类。
典型的Servlet的处理流程:
Servlet 2.X:项目目录结构必须要有WEB-INF,web.xml等文件夹和文件,在web.xml中配置servlet,filter,listener,以web.xml为java web项目的统一入口
Servlet 3.X:项目中可以不需要WEB-INF,web.xml等文件夹和文件,在没有web.xml文件的情况下,通过注解实现servlet,filter, listener的声明,当使用注解时,容器自动进行扫描。
同时Tomcat8.5进行了大量的代码重构,对比与7.0的版本,也符合Tomcat未来的代码架构体系。但是Tomcat的核心和主体架构还是一直保持这样的。
一般启动
Windows下:startup.bat
Linux下:startup.sh
IDE中启动
嵌入式启动
启动SpringBoot
Debug启动
在项目发布后,我们有时候需要对基于生产环境部署的应用进行调试,以解决在开发环境无法重现的BUG。这时我们就需要用到应用服务器的远程调试功能,这个主要是基于JDK提供的JPDA(Java Platform Debugger Architecture,Java平台调试体系结构)。
直接丢文件夹、war、jar到webapps目录,tomcat会根据文件夹名称自动生成虚拟路径,简单,但是需要重启Tomcat服务器,包括要修改端口和访问路径的也需要重启。
config/server.xml中的Host加入一个Context(指定路径和文件地址),例如:
即"/index"这个虚拟路径映射到了"F:\work_space\xxxx"目录下(war会解压成文件),修改完servler.xml需要重启tomcat 服务器。
conf/Catalina/localhost中创建xml文件,访问路径为文件名,例如:
在localhost目录下新建demo.xml,内容为:
不需要写path,虚拟目录就是文件名demo,path默认为/demo,添加demo.xml不需要重启 tomcat服务器。
startup,主要是检查 catalina 的执行所需环境,并调用 catalina,启动 tomcat。
catalina,真正启动 tomcat,可以在里面设置JVM参数。
shutdown,关闭 tomcat。
version:查看当前tomcat的版本号,
configtest:校验tomcat配置文件server.xml的格式、内容等是否合法、正确。
service:安装tomcat服务,可用net start tomcat 启动
脚本version.sh、startup.sh、shutdown.sh、configtest.sh都是对catalina.sh的包装,内容大同小异,差异在于功能介绍和调用catalina.sh时的参数不同。
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
Host>
Engine>
Service>
Server>
存放web项目的目录,其中每个文件夹都是一个项目。
Tomcat自带一些项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。http://localhost:8080/examples,进入示例项目。
Tomcat的类库。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中。
Server是最顶级的组件,它代表Tomcat的运行实例,它掌管着整个Tomcat的生死大权(与上面的server.xml对应)。
一个概念,一个Service维护多个Connector和一个Container
链接器:监听转换Socket请求,将请求交给Container处理,支持不同协议以及不同的I/O方式。
Connector链接器封装了底层的网络请求(Socket请求及相应处理),提供了统一的接口,使Container容器与具体的请求协议以及I/O方式解耦。
Connector将Socket输入转换成Request对象,交给Container容器进行处理。处理请求后,Container通过Connector提供的Response对象将结果写入输出流。
因为无论是Request对象还是Response对象都没有实现Servlet规范对应的接口,Container会将它们进一步分装成ServletRequest和ServletResponse。
表示能够执行客户端请求并返回响应的一类对象,其中有不同级别的容器:Engine、Host、Context、Wrapper
Tomcat组件间可以共享的线程池
用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。
Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。
Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。
Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。
path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。
构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost().执行业务逻辑、数据存储等程序。
Context把执行完之后的HttpServletResponse对象返回给Host。
Host把HttpServletResponse对象返回给Engine。
Engine把HttpServletResponse对象返回Connector。
Connector把HttpServletResponse对象返回给客户Browser。
以下是server.xml中的一段:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
什么是AJP?
Tomcat最主要的功能是提供Servlet/JSP容器。但在对静态资源(如HTML文件或图像文件)的处理速度,以及提供的Web服务器管理功能方面都不如其他专业的HTTP服务器,如IIS和Apache服务器。
因此在实际应用中,常常把Tomcat与其他HTTP服务器集成。对于不支持Servlet/JSP的HTTP服务器,可以通过Tomcat服务器来运行Servlet/JSP组件。
AJP链接器可以让Tomcat通过AJP协议和另一个web容器进行交互。
HTTP/1.1下配置IO
对于I/0选择,要根据业务场景来定。一般高并发场景下,APR和AIO的性能要优于NIO,(linux操作系统并没有真正实现AIO,所以一般linux上推荐使用NIO。如果是APR的话,需要安装APR库,而Windows上默认安装了)。
APR(Apache Portable Runtime):
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />
使用线程池:
server.xml 已经写好了如何配置,只需要取消注释就好了。
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
maxThreads="150" >
Connector>
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
certificateFile="conf/localhost-rsa-cert.pem"
certificateChainFile="conf/localhost-rsa-chain.pem"
type="RSA" />
SSLHostConfig>
Connector>
Linux如果安装了apr和native,Tomcat直接启动就支持APR。(安装方法:http://my.oschina.net/lsw90/blog/181161)
NIO:
最大连接数:10000
线程池:200
队列长度:100
1个线程 Acceptor 负责接收连接 Channel 到 accept 队列。2个线程 Poller 负责轮询。轮询到就绪的读/写创建 SocketProcessor 交给线程池 Executor 去执行。在 Executor 的线程中,会完成从 socket 中读取 HttpRequest 解析成 HttpServletRequest 对象,分派到相应的 servlet 并完成逻辑,然后将 Response 通过 socket 发回 client。在从 socket 中读数据和往 socket中写数据的过程,并没有像典型的非阻塞的 NIO 的那样,注册 OP_READ 或 OP_WRITE 事件到主 Selector,而是直接通过 socket 完成读写,这时是阻塞完成的。