Tomcat简单介绍

19 篇文章 0 订阅

Tomcat是拿JAVA写的,跑在JVM上的应用。

结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • Tomcat最顶层容器叫Server,代表整个服务器,

  • Server里可以包含多个Service。Service的默认名为Catalina。除了Service之外,还会有一些Server级别的Listener设置,比如说org.apache.catalina.core.AprLifecycleListener,负责APR操作系统库的加载。另外还有GlobalNamingResources,定义一些公用的Resource,比如JNDI连接。

  • 一个Service只有一个Container,可以有多个Connector。一个Container只有一个Engine,Engine的默认名也为Catalina,Engine里面可以有多个Host,每个Host(虚拟主机,站点)下可以有多个Context(代表一个应用),每个Context下可以有过个Wrapper(每个封装一个Servlet)。defaultHost是默认主机,如果请求没有指定主机,则交给默认主机(HOST)进行处理。分配是根据访问的网址和hostname是否能对上。比如用户访问网址www.a.com,那么就优先选择www.a.com这个name的HOST,如果没有,则访问defaultHost。一个host下面可以有多个context。每个context代表一个应用。host将请求转发给context依据是context中配置的contextpath。

  • Catalina,这个岛在洛杉矶附近的太平洋上,被誉为美国最美丽的岛屿。

    <Engine name="Catalina" defaultHost="localhost">
      <!-- Use the LockOutRealm to prevent attempts to guess user passwords
           via a brute-force attack -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="false">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>

tomcat支持多种Realm:

  • JDBCRealm
  • DataSourceRealm
  • JNDIRealm
  • UserDatabaseRealm
  • MemoryRealm
  • JAASRealm
  • CombinedRealm
  • LockOutRealm

这些Realm中应该配置用户名和密码,用于使用Resource。(如JNDI)。

Tomcat应用启动流程

应用的加载从web.xml开始,里面的配置如下

  • display-name 应用的名字
  • listener 事件监听支持
  • context-param的初始化参数。比如说contextConfigLocation是springmvc和context之间的关键配置
  • servlet DispatcherServlet就是一个servlet

具体流程如下:

  1. Tomcat 会创建一个 ServletContext(Servlet 上下文),此 Web 项目的所有部分都将共享该上下文。
  2. 容器将context-param>转化为键值对,并交给ServletContext.
  3. 容器创建listener中的类实例,即创建监听
  4. 通过实现ServletContextListener接口中的contextInitialized方法,你可以在此时催context进行一些操作。此时所有servlet和filter都没有被创建,但是应用已经做好了进行服务的准备。此时你可以进行一些比如打开数据库连接的操作。你可以有多个listener,按顺序执行。注意,如果你在后续的listener中需要spring环境的支持,请务必在之前添加如下listener
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

该监听器会根据你在xml中配置的contextConfigLocation初始化springcontext。

  1. 容器初始化完毕,初始化连接器,并在初始化完成后接收客户请求。
  2. 随时客户访问,创建filter和servlet。如果你并没有在listener中完成springcontext的初始化,此时,创建DispatcherServlet servlet时也会初始化spring。
    <servlet>
        <servlet-name>remote</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext-controller.xml,/WEB-INF/remote-servlet.xml</param-value>
        </init-param>
        <!-- 配置该Servlet随应用启动时候启动 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

servlet初始化时会执行serlet中的init方法。我们以DispatcherServlet为例查看其过程:

    public final void init() throws ServletException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
        }

        try {
            PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
            //将当前Servlet转化为一个Wrapper
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            //属性注入
            bw.setPropertyValues(pvs, true);
        } catch (BeansException var4) {
            this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            throw var4;
        }

        this.initServletBean();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
        }

    }

SPRING MVC的具体请参考
https://blog.csdn.net/define_us/article/details/80829707

内部的线程

在这里插入图片描述
Acceptor类实现了Runnable接口,主要用于接收网络请求,建立连接,连接建立之后,将一个SocketChannel对象包装成一个NioChannel(NIO模式的情况下),并注册到Poller中。由Poller线程来负责执行数据的读取和业务执行。

Connector(BIO,NIO,APR三种模式)

BIO 一个线程处理一个请求。当并发很高时,线程数非常高。NIO 采用JAVA NIO模式(N代表New而非non-blocking。每次说到这我都要提示,起名字的人造了多大孽啊),实际上是BIO的多路复用器模式。APR 在操作系统层面解决IO的问题。
在代码中实际对应Connector内部使用endpoint,分别为JIoEndpoint,NioEndpoint,AprEndpoint。

配置在server.xml文件中。

<Connector port="8180" connectionTimeout="10000" redirectPort="8443" maxThreads="1400" minSpareThreads="20" acceptCount="50" protocol="org.apache.coyote.http11.Http11NioProtocol" />

一个tomcat线程可以配置多个Connector,每个Connector对应唯一的端口。

即使使用NIO模式,也赶不上netty的性能。这是因为netty不用遵循servlet规范,可以最大化发挥NIO的特性,性能更高一些。但对于多数业务来讲tomcat的connector已经足够了。tomcat使用的是Apache的MINA网络库。

Tomcat的启动日志可以看到具体采用哪一种

Starting ProtocolHandler ["http-bio-8080"]
Starting ProtocolHandler ["http-nio-8080"]
Starting ProtocolHandler ["http-apr-8080"]
BIO模式

在BIO的专门负责socket建立的Acceptor线程的逻辑里,将socket封装成一个task(对应的是JIoEndpoint.SocketProcessor这个类)提交给线程池处理。
在这里插入图片描述
服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

NIO模式

服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

APR模式

服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。此时tomcat会通过JNI调用本地库来解决连接问题。一个请求一个线程。
对ARP支持,需要安装以下本地库:

APR library
JNI wrappers for APR used by Tomcat (libtcnative)
OpenSSL libraries
对比

BIO:适用连接数较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中。
NIO:适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂。
APR:适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂。

参数

  • 内存优化
    catalina.sh文件中修改启动参数
  • 连接数优化
    conf/server.xml文件中进行修改
minProcessors:最小空闲连接线程数,用于提高系统处理性能,默认值为10。

maxProcessors:最大连接线程数,即:并发处理的最大请求数,默认值为75。

acceptCount:允许的最大连接数,应大于等于maxProcessors,默认值为100。accept队列的长度;当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。默认值是100。

maxConnections: Tomcat在任意时刻接收和处理的最大连接数。当Tomcat接收的连接数达到maxConnections时,Acceptor线程不会读取accept队列中的连接;这时accept队列中的线程会一直阻塞着,直到Tomcat接收的连接数小于maxConnections。如果设置为-1,则连接数不受限制。

maxThreads:请求处理线程的最大数量。默认值是200(Tomcat7和8都是的)。如果该Connector绑定了Executor,这个值会被忽略,因为该Connector将使用绑定的Executor,而不是内置的线程池来执行任务。

Session的概念

Http协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;
Session的主要目的就是为了弥补Http的无状态特性。简单的说,就是服务器可以利用session存储客户端在同一个会话期间的一些操作记录;
在Tomcat中Session id用JSESSIONID表示,客户端网页浏览器通过cookie保存本次会话的JSESSIONID。

是一块在服务器开辟的内存空间,其存储结构为ConcurrentHashMap;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值