JavaWeb项目没有main怎么跑
写了这么多的servlet,突然发现,好像找不到程序的入口?(比如main()???)
main()在Tomcat里
首先必须确认,main()是存在的
在哪里呢?在我们部署的Tomcat容器中
main()具体在Tomcat的BootStrap类里面,web应用启动是不会执行类中的main方法的,因为只会调用Tomcat的main,然后通过web.xml的配置去加载其它类,我们平时写的main(),只是用来测试用的
Tomcat也是个Java程序
Java程序跑起来,一般是通过主类的main方法启动的
对于Web应用,是tomcat中按照Servlet等规范实现,我们的应用中写规范定义好的API逻辑,Tomcat按请求去调用这些Servlet,从而启动Web应用
部署
我们用 Java 开发 Web 应用,开发完成,编译打包以后得到的是一个 war 包,这个 war 包放入 Tomcat 的应用程序路径下,启动 Tomcat 就可以通过 HTTP 请求访问这个 Web 应用了
Tomcat:从启动到运行
首先,我们是通过执行 Tomcat 的startup
的Shell 脚本启动 Tomcat 的,而在 Shell 脚本里,其实启动的是 JVM。Tomcat 启动以后,其实在操作系统里看到的是一个JVM 进程。
JVM进程启动以后,类加载器加载 class 进来执行,首先加载的就这个org.apache.catalina.startup.Bootstrap类,这个类里面有一个main()函数,是整个 Tomcat 的入口函数,JVM 虚拟机会启动一个主线程从这个入口函数开始执行。
主线程从 Bootstrap 的 main() 函数开始执行,初始化 Tomcat 的运行环境,这时候就需要创建一些线程,比如负责监听80端口的线程(HTTP),处理客户端连接请求的线程,以及执行用户请求的线程。创建这些线程的代码是 Tomcat代码的一部分。
初始化运行环境之后,Tomcat就会扫描 Web 程序路径,扫描到开发的 war 包后,再加载 war 包里的类到 JVM。因为 Web 应用是被 Tomcat 加载运行的,所以我们也称 Tomcat 为 Web 容器。
如果有外部请求发送到 Tomcat,也就是外部程序通过 80 端口和 Tomcat 进行 HTTP 通信的时候,Tomcat 会根据 war 包中的 web.xml 配置,决定这个请求 URL 应该由哪个 Servlet 处理,然后 Tomcat 就会分配一个线程去处理这个请求,实际上,就是这个线程执行相应的 Servlet 代码。(关于线程的分配,Tomcat使用了线程池)
Tomcat启动之初,会根据配置server.xml等xml及webapps下部署的app,在内存中建立起一个全局的host->context->servlet的映射关系,Tomcat有一个connector组件,负责接收socket,并进行HTTP协议的解析,然后从进程全局的线程池中随机获取一个线程,根据解析出的URL,在前面的映射关系中定位到相应的servlet进行业务处理
我们开发的应用是一些类, 这些类被Tomcat 加载到这个JVM 里执行,所以,即使这里有多个应用被加载,也只是加载了一些类,我们的应用被加载进来以后,并没有增加 JVM 进程中的线程数,也就是Web应用本身和线程是没有关系的
而 Tomcat 会根据 HTTP请求的URL 执行应用中的代码,这个时候,可以理解成每个请求分配一个线程,每个线程执行的都是我们开发的 Web 代码。(如果 Web 代码中包含了创建新线程的代码,Tomcat 的线程在执行代码时,就会创建出新的线程,这些线程也会被操作系统调度执行。)
运行详情:请求在Tomcat中的运行流程
请求详情:tomcat一次完整请求流程
Tomcat和我们web应用的关系
从 JVM 的角度看,Tomcat 和我们的 Web 应用是一样的,都是一些 Java 代码,但是 Tomcat 却可以加载执行 Web 代码,而我们的代码又不依赖 Tomcat。
关于异常
如果 Tomcat 的线程在执行代码时,代码抛出未处理的异常,那么当前线程就会结束执行,这时控制台看到的异常信息,其实就是线程堆栈信息,线程会把异常信息以及当前堆栈的方法都打印出来。事实上,这个异常最后还是会被 Tomcat 捕获,然后 Tomcat 会给客户端返回一个 500 错误。单个线程的异常不影响其他线程执行,也就是不影响其他请求的处理。
但是如果线程在执行代码的时候,抛出的是JVM 错误,比如OutOfMemoryError,这个时候看起来是应用 crash,事实上是整个进程都无法继续执行了,也就是进程 crash 了,进程内所有应用都不会被继续执行了。