https://blog.csdn.net/fuzhongmin05/article/details/104379514

一个JVM是一个进程,JVM上跑Tomcat,Tomcat上可以部署多个应用。这样的话,每个跑在Tomcat上的应用是一个线程吗?如果一个应用crash了,其他应用也会crash吗?

理解程序运行时的执行环境,直观感受程序是如何运行的,对我们开发和维护软件很有意义。我们以上面这个问题为例,看下Java Web程序的运行时环境是什么样的,来梳理下进程、线程、应用、Web容器、Java虚拟机和操作系统之间的关系。

我们用Java开发Web应用,开发完成,编译打包以后得到的是一个war包,这个war包放入Tomcat的应用程序路径下,启动Tomcat就可以通过HTTP请求访问这个Web应用了。

在这个场景下,进程是哪个?线程有哪些?Web程序的war包是如何启动的?HTTP请求如何被处理?Tomcat在这里扮演的是什么角色?JVM又扮演什么角色?

首先,我们是通过执行Tomcat的Shell脚本启动Tomcat的,而在Shell脚本里,其实启动的是Java虚拟机,大概是这样一个Shell命令:

  1. java org.apache.catalina.startup.Bootstrap "$@" start
  • 1

所以我们在Linux操作系统执行Tomcat的Shell启动脚本,Tomcat启动以后,其实在操作系统里看到的是一个JVM虚拟机进程。这个虚拟机进程启动以后,加载class进来执行,首先加载的就这个org.apache.catalina.startup.Bootstrap类,这个类里面有一个main()函数,是整个Tomcat的入口函数,JVM虚拟机会启动一个主线程从这个入口函数开始执行。

主线程从Bootstrap的main()函数开始执行,初始化Tomcat的运行环境,这时候就需要创建一些线程,比如负责监听80端口的线程,处理客户端连接请求的线程,以及执行用户请求的线程。创建这些线程的代码是Tomcat代码的一部分。

初始化运行环境之后,Tomcat就会扫描Web程序路径,扫描到开发的war包后,再加载war包里的类到JVM。因为Web应用是被Tomcat加载运行的,所以我们也称Tomcat为Web容器或者Servlet容器。

如果有外部请求发送到Tomcat,也就是外部程序通过80端口和Tomcat进行HTTP通信的时候,Tomcat会根据war包中的web.xml配置,决定这个请求URL应该由哪个Servlet处理,然后Tomcat就会分配一个线程去处理这个请求,实际上,就是这个新线程执行了相应的Servlet代码。如何分配线程呢?Tomcat使用了线程池,在用户发起的一个访问web资源(servlet或者jsp页面)的请求过来时,如果线程池里面有空闲的线程,那么会在线程池里面取一个工作线程来处理该请求,一旦工作线程当前在处理请求(在工作线程中调用servlet的service方法或者doGet/doPost方法),其他请求就不会被分配到该工作线程上,直到该请求处理完成。请求处理完成后,会将工作线程重新加入线程池。

Tomcat启动之初,会根据配置server.xml等xml及webapps下部署的app,在内存中建立起一个全局的host->context->servlet的映射关系,Tomcat有一个connector组件,负责接收socket,并进行HTTP协议的解析,然后从进程全局的线程池中随机获取一个线程,根据解析出的URL,在前面的映射关系中定位到相应的servlet进行业务处理。

Tomcat启动的时候,启动的是JVM进程,这个进程首先是执行JVM的代码,而JVM会加载Tomcat的class执行,并分配一个主线程,这个主线程会从main函数开始执行。在主线程执行过程中,Tomcat的代码还会启动其他一些线程,包括处理HTTP请求的线程。

而我们开发的应用其实就是一些类, 这些类被Tomcat加载到JVM里执行,所以,即使这里有多个应用被加载,也只是多加载了一些类而已,我们写的类被加载进来以后,并没有增加JVM进程中的线程数,也就是Web应用本身和线程是没有关系的。

而Tomcat会根据HTTP请求的URL执行应用中的代码,这个时候,可以理解成每个请求分配一个线程,每个线程执行的都是我们开发的Web代码。如果Web代码中包含了创建新线程的代码,Tomcat的线程在执行代码时,就会创建出新的线程,这些线程也会被操作系统调度执行。

如果Tomcat的线程在执行代码时,代码抛出了未处理的异常,那么当前线程就会结束执行,这时控制台看到的异常信息,其实就是线程堆栈信息,线程会把异常信息以及当前堆栈的方法都打印出来。事实上,这个异常最后还是会被Tomcat捕获,然后Tomcat会给客户端返回一个500错误。单个线程的异常不会影响其他线程执行,也就是不影响其他请求的处理。但是如果线程在执行代码的时候,抛出的是JVM错误,比如OutOfMemoryError,这个时候看起来是应用crash,事实上是整个进程都无法继续执行了,也就是进程crash了,进程内所有应用都不会被继续执行了。

从JVM的角度看,Tomcat和我们的Web应用是一样的,都是一些Java代码,但是Tomcat却可以加载并执行Web代码,而我们的代码又不依赖Tomcat。

那么将Web应用部署在Tomcat这样的容器下有什么好处呢?我觉得可以使开发者聚焦业务逻辑,而不用去关心HTTP协议方面的事情。比如,普通的HTTP请求就是一段有格式的文本,服务器需要去解析这段文本才能知道用户请求的内容是什么,如果我们为了写一个Web应用,还要去解析HTTP协议相关的内容,那会增加很多工作量。如果我们写的Web应用不大,不夸张的说,项目中对HTTP提供支持的代码会比业务代码还要多,这岂不是得不偿失。而在现实中,有现成的框架可用,并不需要自己造轮子。如果我们基于Servlet规范实现Web应用的话,HTTP协议的处理过程就不需要我们参与了。这些工作交给Servlet容器就行了,我们只需要关心业务逻辑怎么实现即可。Spring MVC就是基于Servlet实现的框架。

Java Web程序在Tomcat上是如何运行的的更多相关文章

  1. eclipse配置tomcat,并部署一个Java web项目到tomcat上

    引用链接:https://blog.csdn.net/cincoutcin/article/details/79408484 eclipse配置tomcat 1.windows——preference ...

  2. Java Web程序工作原理

    Web开发的最重要的基本功能是HTTP:Java Web开发的最重要的基本功是Servlet Specification.HTTP和Servlet Specitication对于Web Server和 ...

  3. 在Java Web程序中使用监听器可以通过以下两种方法

    之前学习了很多涉及servlet的内容,本小结我们说一下监听器,说起监听器,编过桌面程序和手机App的都不陌生,常见的套路都是拖一个控件,然后给它绑定一个监听器,即可以对该对象的事件进行监听以便发生响 ...

  4. @Java web程序员,在保留现场,服务不重启的情况下,执行我们的调试代码(JSP 方式)

    一.前言 类加载器实战系列的第六篇(悄悄跟你说,这篇比较水),前面5篇在这里: 实战分析Tomcat的类加载器结构(使用Eclipse MAT验证) 还是Tomcat,关于类加载器的趣味实验 了不得, ...

  5. 在Java Web程序中使用Hibernate

    在Java Web程序中使用Hibernate与普通Java程序一样.本文中将使用Servlet和JSP结合Hibernate实现数据库表的增删改查操作. Web程序中,hibernate.cfg.x ...

  6. 使用spring等框架的web程序在Tomcat下的启动顺序及思路理清

    大牛请绕过,此文仅针对自己小白水平,对web程序的启动流程做个清晰的回顾. 一.使用spring等框架的web程序在Tomcat下的启动流程 1)Tomcat是根据web.xml来启动的.首先到web ...

  7. JAVA Web 之 struts2文件上传下载演示(二)(转)

    JAVA Web 之 struts2文件上传下载演示(二) 一.文件上传演示 详细查看本人的另一篇博客 http://titanseason.iteye.com/blog/1489397 二.文件下载 ...

  8. JAVA Web 之 struts2文件上传下载演示(一)(转)

    JAVA Web 之 struts2文件上传下载演示(一) 一.文件上传演示 1.需要的jar包 大多数的jar包都是struts里面的,大家把jar包直接复制到WebContent/WEB-INF/ ...

  9. java Web程序使用wro4j合并、压缩js、css等静态资源

    在Web项目中,js.css合并压缩,不仅有利于减少Http请求数量.减少宽带资源占用,还能有效的管理各种js.css的引入,使整个项目更加有序.而对于访问用户来说,其更大的好处是增加了页面的打开速度 ...

  10. linux tomcat部署含有matlab画图打包的java web程序

    首先说下问题:matlab可以把相关算法代码打包成jar文件共java调用,本例使用的jar文件的作用是画图并保存,然后部署在linux的tomcat中进行发布.这里出现了一个问题,具体如下:linu ...

随机推荐

  1. .Net FrameWork下面如何生成AOT呢?

    前言 其实AOT预编译,在.Net FrameWorker1.0里面就有了.它叫做Ngen,只不过当时叫做生成本机映像,实际上还是一个东西,也就是预编译.本篇来看下. 概括 1.介绍 现在的现代化的. ...

  2. 大白话讲讲 Go 语言的 sync.Map(一)

    阅读本文大约需要 4.25 分钟. 程序是枯燥乏味的. 在讲 sync.Map 之前,我们先说说什么是 map(映射). 我们每个人都有身份证号码,如果我需要从身份证号码查到对应的姓名,用 map 存 ...

  3. 【Dotnet 工具箱】推荐一个使用 C# 开发的轻量级压测工具

    你好,这里是 Dotnet 工具箱,定期分享 Dotnet 有趣,实用的工具和组件,希望对您有用! 轻量级压测工具 LoadTestToolbox 是一个使用 C# 开发的轻量级压测工具,基于 .NE ...

  4. Robot Framework 自动化测试部署常见问题及处理方法(一)

    1.在Python>>Scripts中运行python ride.py时报错 现象: 1 Traceback (most recent call last): 2 File "E ...

  5. webpack配置文件的分离

    配置文件的分离 目的就是让开发环境, 生产环境,测试环境的配置分隔开 步骤一: 在项目根目录下创建一个 build 文件夹专门用来存放配置文件,再创建三个js文件, base.config.js 文件 ...

  6. protolator - Protobuf <==> json

    github.com/hyperledger/fabric-config/protolator 是 Hyperledger Fabric 中的一个 Go 包,用于将 Protocol Buffers( ...

  7. Parallel 与 ConcurrentBag<T> 这对儿黄金搭档(C#)【并发编程系列】

    〇.前言 日常开发中经常会遇到数据统计,特别是关于报表的项目.数据处理的效率和准确度当然是首要关注点. 本文主要介绍,如何通过 Parallel 来并行处理数据,并组合 ConcurrentBag&l ...

  8. [selenium]取值元素文本属性样式

    前言 版本: python:3.9 selenium:4.1.5 获取元素文本 text = driver.find_element(by=By.XPATH, value=""). ...

  9. shell命令-lsof

    前言 lsof是系统管理常用命令,其名指的是list open files,列出打开的文件,而在linux系统,一切皆文件. centos7安装:yum install -y lsof 获取网络信息 ...

  10. ctfshow--web入门--文件上传

    ctfshow--web入门--文件上传 web151(前端校验) 题目中提示前端检验不可靠,应该对前端检验进行绕过 检查前端代码进行修改,使php文件可以通过前端校验,成功上传后进行命令执行,找到f ...