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命令:

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. Redis的设计与实现(3)-字典

    Redis 的数据库使用字典实现, 对数据库的增, 删, 查, 改也是构建在对字典的操作之上的. 字典是哈希键的底层实现之一: 当一个哈希键包含的键值对比较多, 又或者键值对中的元素都是比较长的字符串 ...

  2. MyBatis(RowBounds)分页了解内容

    RowBounds 不在使用SQL实现分页 1.接口 List<User> getUserByRowBounds(); 2.mapper.xml <select id="g ...

  3. Linux下实现程序开机自启(rc.local 和 systemctl)

    需求: 实现了一个程序,需要在ubuntu上跑起来.能开机自启,且崩溃了也能自己重启.有两种实现方式,个人推荐第二种. 方式1: 实现方式: 直接将要启动程序的运行命令加在 /etc/rc.local ...

  4. 关于selenium WebDriverException: Message: unknown error: DevToolsActivePort file doesnt exist 的解决方案

    文章参考: https://hant-kb.kutu66.com/others/post_13460379 在浏览器设置参数时加入如下两行代码 1 # 取消沙盒模式 2 options.add_arg ...

  5. 【干货】浅谈如何给.net程序加多层壳达到1+1>2的效果

    软件破解分白盒和黑盒两种方式. 白盒破解:白盒破解是指对软件进行破解时,攻击者可以访问软件的内部结构和源代码.这种破解方式通常发生在软件的开发者.技术人员或软件公司内部.攻击者使用这些详细信息来理解软 ...

  6. 记录一次AutoMapper注册报错

    通常,.Net5我们注册服务是这样的. //添加AutoMapper var automapperConfog = new MapperConfiguration(config => { con ...

  7. mybatis数据库字段自动填充

    背景描述 目前,大多数项目的数据库设计,都会添加一些公共字段,比如version(版本号).deleted(逻辑删除标识).create_time.update_time.create_by.upda ...

  8. 快速了解C#接口(Interface)

    Runoob 接口定义了所有类继承接口时应遵循的语法合同.接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分. 接口定义了属性.方法和 ...

  9. 快速搭建SpringBoot3.x项目

    写在前面 上一小节中我们从0到1 使用Vite搭建了一个Vue3项目,并集成了Element Plus 实现了一个简单的增删改查页面. 这一篇中我们将使用IDEA快速搭建一个SpringBoot3.x ...

  10. 「codeforces - 1394C」Boboniu and String

    link. 注意到 BN-string 长成什么样根本不重要,我们把它表述为 BN-pair \((x, y)\) 即可,两个 BN-strings 相似的充要条件即两者分别映射得到的 BN-pair ...