首页 > 其他分享 >Tomcat原理分析

Tomcat原理分析

时间:2024-04-06 09:23:30浏览次数:25  
标签:分析 包含 Tomcat 对象 线程 原理 Servlet 加载

Tomcat内部结构

内部可以分为两部分:HTTP服务器 + Servlet容器。

这里以内嵌Tomcat为例,启动类为Tomcat

  1. Tomcat里包含一个Server,类型为StandardServer。
  2. StandardServer中包含对个service,类型为StandardService,在创建StandardServer时添加了一个service对象。
  3. StandardService中包含多个Connector,包含一个Engine(类型为StandardEngine)。
  4. Connector中包含一个ProtocolHandler,一般使用Http11NioProtocol类型,它内部又包含NioEndpoint。
  5. StandardEngine内部包含多个child,一般将Host(类型为StandardHost)作为第一个child。
  6. StandardHost内部也包含多个child,一般将StandardContext作为其第一个child。
  7. StandardContext可以看做一个项目,每个项目都有单独的contextPath,单独的ServletContext(具体类型为ApplicationContext)。
  8. StandardContext内部包含多个child,其实都是Wrapper,具体类型为StandardWrapper,Wrapper可以看做一个Servlet的包装器,其中也包含此Servlet的urlMapping,具体属性为mappings。
  9. StandardContext内部的filterDefs属性保存所有的Filter定义,filterMaps保存urlMapping和Filter的对应关系。

StandardEngine,StandardHost,StandardContext,StandardWrapper,这几个Container中都包含一个Pipeline对象,具体类型为StandardPipeline。StandardPipeline中包含一个Valve对象,可以看做一个链表节点

  1. StandardEngine向Pipeline对象设置了StandardContextValve
  2. StandardContextValve设置了StandardHostValve
  3. StandardContext设置了StandardContextValve
  4. StandardWrapper设置了StandardWrapperValve
  1. Connector中包含一个ProtocolHandler,一般使用Http11NioProtocol类型,它内部又包含一个NioEndpoint对象。

Tomcat启动流程

  1. Tomcat的start()方法
  2. 先调用StandardServer的init()方法,其中又会调用它的内部组件service的init流程,没啥重要的,都是一些MBean监控相关的处理。
  3. 在NioEndpoint的start()方法流程中,会创建ServerSocketChannel对象,接收客户端请求,并创建ThreadPoolExecutor对象,此类继承Java中的ThreadPoolExecutor类
  4. 开启Acceptor线程,它的工作:
    • 调用AbstractEndpoint的serverSocketAccept()方法,对于NioEndpoint来说,就是ServerSocketChannel的accept()。
    • 调用AbstractEndpoint的setSocketOptions()方法,根据accept的SocketChannel创建NioSocketWrapper并注册到Poller对象中
  5. 开启Poller线程,它的工作:
    • 一直监听SynchronizedQueue队列(等待Acceptor线程注册),得到NioSocketWrapper,向JavaNIO中Selector注册读事件
    • 监听Selector读和写,创建SocketProcessorBase对象,具体类型为SocketProcessor,这是一个Runnable,交给上面创建的线程池来处理。
  6. 向Selector注册写事件是通过Poller的addEvent()方法来实现的

Acceptor和Poller之间通过queue通信,可以看做生产者/消费者模式。

Tomcat处理请求的流程

  1. Acceptor线程接收到SocketChannel对象,交给Poller线程处理
  2. Poller线程将SocketChannel包装成NioSocketWrapper对象,在包装到一个SocketProcessor中,它可以看做一个任务,交给线程池处理
  3. SocketProcessor在处理的过程中会创建Http11Processor对象
  4. Http11Processor通过内部的Http11InputBuffer来解析HTTP请求,创建出Request和Response对象。
  5. 交给CoyoteAdapter对象的service()方法来处理
    • 先找到满足请求路径的Servlet
         //通过Mapper对象根据请求url找到符合要求的Servlet,具体为internalMapWrapper()方法
      connector.getService().getMapper().map(serverName, decodedURI,
                    version, request.getMappingData());
      
    • 调用Servlet
      //StandardService的container为StandardEngine,通过pipeline最终会调用
      connector.getService().getContainer().getPipeline().getFirst().invoke(
                       request, response);
      
    StandardEngineValve -> StandardHostValve -> StandardContextValve -> StandardWrapperValve
  6. StandardWrapperValve来创建Servlet对象,初始化,通过ApplicationFilterFactory来创建ApplicationFilterChain对象(过滤器链),过滤器信息是从StandardWrapper的parent组件StandardContext中获取的。
  7. 执行过滤器链,依次执行Filter的doFilter()方法,然后执行Servlet的service()方法

HTTP服务器和Servlet容器之间通过CoyoteAdapter对象关联起来。

Tomcat为什么不使用Netty作为连接器

  1. 第一个原因是Tomcat的连接器性能已经足够好了,同样是Java NIO编程,套路都差不多。
  2. 第二个原因是Tomcat做为Web容器,需要考虑到Servlet规范,Servlet规范规定了对HTTP Body的读写是阻塞的,因此即使用到了Netty,也不能充分发挥它的优势。所以Netty一般用在非HTTP协议和Servlet的场景下。

SpringBoot内嵌Tomcat为何不扫描WebServlet等Servlet3.0注解

Embedded Tomcat does not honor ServletContainerInitializers

为什么嵌入式Tomcat不会扫描ServletContainerInitializer类,是因为Context中没有添加ContextConfig这个LifecycleListener,没有使用Tomcat那一套流程,SpringBoot自己定义了一套规范,如ServletContextInitializer接口及@ServletComponentScan注解。

我们可以通过以下方式添加,但不确定是否有什么冲突和隐患。

@Bean
public TomcatContextConfigWebServerCustomizer websocketServletWebServerCustomizer() {
  return new TomcatContextConfigWebServerCustomizer();
}

public class TomcatContextConfigWebServerCustomizer
    implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, Ordered {

  @Override
  public void customize(TomcatServletWebServerFactory factory) {
    factory.addContextCustomizers((context) -> context.addLifecycleListener(new ContextConfig()));
  }

  @Override
  public int getOrder() {
    return 0;
  }

}

Tomcat中的线程池

具体类为 ThreadPoolExecutor(tomcat包下)。

  • java中的线程池默认是到达核心线程数之后添加队列,队列满了之后创建新的线程直到最大线程数,再之后执行拒绝策略
  • Tomcat中的流程为,到达核心线程数之后创建新的线程直到最大线程数,之后再添加队列,队列满了之后执行拒绝策略,通过重写execute()方法和重写队列的offer()方法来实现。当核心线程数小于最大线程数,就添加队列失败。

原因:

  • JDK默认提供的线程池为CPU密集型
  • Tomcat需要的是IO密集型

Tomcat中的类加载器

具体类为 WebappClassLoaderBase

  1. 先查本地cache是否已经加载过此类
  2. 查询系统类加载器是否已经加载过
  3. 如果都没有,交给扩展类加载器加载(它会委托根类加载器加载),这个是为了避免覆盖JDK核心类。
  4. 扩展类加载器加载失败,在本地Web应用下查找(自己加载)
  5. 没找到,交给系统类加载器加载

和双亲委派机制不同的地方在于,先自己尝试加载,再交给父类加载器加载。

关于Tomcat中的Session实现原理

  • 使用StandardManager来管理Session,父类ManagerBase中的sessions(Map类型)来保存所有Session。
  • 使用StandardSessionIdGenerator来生成sessionid
  • 创建一个空的Session对象,在设置Id时,向ManagerBase中的sessions中添加自身。
  • Session的过期清理是借助Tomcat的热加载机制来处理的,具体为ManagerBase的backgroundProcess()方法,每隔60秒检查一次,当然每次具体使用时也会检查。

参考

tomcat源码阅读
Tomcat NIO 模型的实现
原生线程池这么强大,Tomcat 为何还需扩展线程池?
深入拆解 Tomcat & Jetty-极客时间

标签:分析,包含,Tomcat,对象,线程,原理,Servlet,加载
From: https://www.cnblogs.com/strongmore/p/18037761

相关文章

  • 【华为OD机试真题】211、最优资源分配、芯片资源占用 | 机试真题+思路参考+代码分析(C
    文章目录一、题目......
  • 官方权威分析抖音有效粉丝秘笈:巨量千川投流,抖音涨粉首选!
    在抖音涨粉的道路上,选择合适的方式至关重要。而官方的巨量千川投流作为一种快速涨粉的利器,拥有着诸多优势,成为创作者们的首选。首先,它的最大优势在于其正规性。通过广告投流的方式,所增加的粉丝都是真实用户,对您的账号没有任何不良影响,让您可以安心使用。其次,官方粉丝的稳定性......
  • 数据结构篇:跳跃表与B+树的对比与优劣分析
       本文旨在探讨跳跃表的特性及其在实际应用场景中的作用,同时对其与B+树进行比较,以帮助更好地理解和运用这两种数据结构。跳跃表什么是跳跃表(skiplist)        跳跃表是一种基于跳跃链表的有序数据结构,它是一种多层链表,每一层都是一个有序的链表。表的每一层......
  • PWM原理及其应用
    什么是PWM   PWM(PulseWidthModulation)简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在测量、通信、工控等方面。PWM的频率    是指在1秒钟内,信号从高电平到低电平再回到高电平的次数,也就是说一秒钟PWM有多少个周期,单位H......
  • 记一次dlopen使用问题导致Framework重启,tombstones、pmap与反汇编分析(上)
    关键词:AndroidFramework动态库动态链接Binder1、事件起因AndroidStudio一次更新后发现installApp,设备就重启了,跑了一遍开机动画但不是从开机第一屏开始重启,tombstones内容查看发现是surfaceflinger挂在libbinder.so,那installapp做了什么这个不得而知,理论上有问题应该挂的......
  • AbstractQueuedSynchronizer源码分析
    在分析Java并发包java.util.concurrent源码的时候,少不了需要了解AbstractQueuedSynchronizer(以下简写AQS)这个抽象类,因为它是Java并发包的基础工具类,是实现ReentrantLock、CountDownLatch、Semaphore、FutureTask等类的基础。在分析Java并发包java.util.concurren......
  • OAuth的工作原理
    用户请求授权:用户在第三方应用程序中请求访问受保护的资源。由于这些资源受到保护,因此需要进行授权。授权服务器认证:第三方应用程序将用户重定向到授权服务器。授权服务器要求用户进行身份验证,这通常涉及到输入用户名和密码或其他认证方式。用户授权:一旦用户通过身份验证,授权服......
  • 【移动安全】对webview漏洞的一些分析
    这次分析的app如下:打开发现该app发现需要登录界面:拖进jadx看一下,先来看一下AndroidManifest.xml文件发现有两个类是导出,再来分析这两个类这个RegistrationWebView类利用webview.loadUrl进行加载网页publicclassRegistrationWebViewextendsAppCompatActivity{/*......
  • 人工智能基础概念5:使用L1范数惩罚进行Lasso回归(正则化)解决机器学习线性回归模型幻觉和
    一、引言在老猿CSDN的博文《人工智能基础概念3:模型陷阱、过拟合、模型幻觉》中介绍了通过L1或L2正则化来限制模型的复杂度来解决过拟合的问题,老猿当时并不了解这背后的原理,这2天通过查阅资料终于明白了相关知识,在此一L1正则化来分享一下相关原理。二、相关概念2.1、......
  • tomcat 8.5 本地编译代码
    1、下载地址:https://tomcat.apache.org/download-80.cgi 2运行1)解压zip压缩包2)目录创建进入解压目录,并创建一个目录,命名为home,并将conf、webapps目录移入home目录中3)修改成maven项目在当前目录下创建一个pom.xml文件,引入tomcat的依赖包,改造成maven项目,pom文件......