Tomat启动-源码跟踪
《看透SpringMVC源码分析与实践》
Tomcat源码分析—-初始化与启动
tomcat环境搭建
源码下载
由于项目使用的tomcat版本时7.47
,从apache svn check代码,svn地址是:
http://svn.apache.org/repos/asf/tomcat/tc7.0.x/tags/TOMCAT_7_0_47/。
idea环境搭建
idea搭建tomcat7开发环境,参照基于IntelliJ IDEA 15.0.2的Tomcat7.0.69源码运行环境搭建
- 将tomcat_7_0_47转换为Maven工程,添加 pom.xml 文件。
- 在tomcat_7_0_47的源码根目录下,新建 catalina-base目录,作为Tomcat的工作目录
- 将 conf、logs
(新建目录)
、webapps、work(新建目录)
文件夹,移入 catalina-base目录 - idea引入import Project –>pom.xml
- 删除无用的文件、文件夹(
非强迫症患者,此步可跳过
)。删除bin/,modules/,res/,test/,build.properties等文件
,最终的项目结构如下图:
- 运行
org.apache.catalina.startup.Bootstrap.main()
,jvm参数为:-Dcatalina.base="你的工程目录\catalina-base"
,log配置为output to file:你的工程目录\catalina-base\logs
可能会报错:
java.lang.ClassNotFoundException: websocket.drawboard.DrawboardContextListener
只需将/webapps/example 文件夹删除删除即可。
tomcat启动
tomcat的启动入口是org.apache.catalina.startup.Bootstrap.main()
Bootstrap.main()
//org.apache.catalina.startup.Bootstrap
public static void main(String args[]) {//创建一个Bootstrap,当bootstrap 初始化完成之后,再赋值给daemonif (daemon == null) {//try-catch 省略....Bootstrap bootstrap = new Bootstrap();//调用init()方法,初始化ClassLoader,并用ClassLoader穿件Catalina实例,赋给catalinaDaemon变量。bootstrap.init();daemon = bootstrap;} else {Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);}try {//默认command为startString command = "start";if (args.length > 0) {//取args最后一个参数,为commandcommand = args[args.length - 1];}if (command.equals("startd")) {args[args.length - 1] = "start";daemon.load(args);daemon.start();} else if (command.equals("start")) {//start比 startd多了一行代码: daemon.setAwait(true);daemon.setAwait(true);daemon.load(args);//调用start方法...daemon.start();}//省略,stopd,stopelse if (command.equals("configtest")) {daemon.load(args);if (null==daemon.getServer()) {System.exit(1);}System.exit(0);}} catch (Throwable t) {//省略log....System.exit(1);}}
main方法可传入的参数有
startd、stopd、start、stop,startd和start的区别是设置了一个await的boolean变量为true
main方法内容分为三部分:
- 首先创建Bootstrap,并执行
init()
方法初始化, - 然后调用
load()
- 最后调用
start()
方法。
Bootstrap.init()
调用Boostrap的init方法主要完成:
- 初始化路径:CATALINA_HOME,CATALINA_BASE
- 初始化类加载器:commonLoader、catalinaLoader、sharedLoader.
- 初始化Boostrap的Catalina对象:通过反射生成Catalina对象,并通过反射调用setParentClassLoader方法设置其父 ClassLoader为
sharedLoader
//org.apache.catalina.startup.Bootstrap
public void init() throws Exception {//设置安装目录:CATALINA_HOMEsetCatalinaHome();//设置工作目录CATALINA_BASEsetCatalinaBase();//初始化classLoadersinitClassLoaders();//主线程的classLoader设置为catalinaLoaderThread.currentThread().setContextClassLoader(catalinaLoader);//安全管理的classLoad设置为catalineLoaderSecurityClassLoad.securityClassLoad(catalinaLoader);//省略log....//load启动类CatalinaClass<?> startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");Object startupInstance = startupClass.newInstance();/* * 反射实现:catalina的ParentClassLoader设置为sharedLoader* catalina.setParentClassLoader(sharedLoader);*/String methodName = "setParentClassLoader";Class<?> paramTypes[] = new Class[1];paramTypes[0] = Class.forName("java.lang.ClassLoader");Object paramValues[] = new Object[1];paramValues[0] = sharedLoader;Method method =startupInstance.getClass().getMethod(methodName, paramTypes);method.invoke(startupInstance, paramValues);catalinaDaemon = startupInstance;}
CATALINA_HOME和CATALINA_BASE区别?
CATALINA_HOME
是Tomcat的安装目录,指向公用信息
的位置,就是bin和lib
的父目录。。
CATALINA_BASE
是Tomcat的工作目录指向每个Tomcat目录私有信息
的位置,就是conf、logs、temp、webapps和work
的父目录。
如果我们想要运行Tomcat 的 多个实例,但是不想安装多个Tomcat软件副本。那么我们可以配置多个工作 目录
,每个运行实例独占一个工作目录,但是共享同一个安装目录
。
tomcat多实例配置
Bootstrap.initClassLoaders()
tomcat的classloader通过conf/catalina.properties
配置,配置内容为:
package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.##classloader 相关
common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
server.loader=
shared.loader=//省略....
initClassLoaders()
方法逻辑
初始化commonLoader ,catalinaLoader ,sharedLoader
//org.apache.catalina.startup.Bootstrap
private void initClassLoaders() {try {//commonLoader 设置父类加载器为null,则为jdk中的commonLoader = createClassLoader("common", null);if( commonLoader == null ) {//若没有配置文件配置,则取SystemClassLoader。commonLoader=this.getClass().getClassLoader();}//catalinaLoader , sharedLoader 设置父类加载器为 commonLoadercatalinaLoader = createClassLoader("server", commonLoader);sharedLoader = createClassLoader("shared", commonLoader);} catch (Throwable t) {handleThrowable(t);log.error("Class loader creation threw exception", t);System.exit(1);}}
SecurityClassLoad.securityClassLoad()
方法逻辑
使用catalinaLoader加载tomcat容器独享
的一些calss,
//org.apache.catalina.security.SecurityClassLoad
public static void securityClassLoad(ClassLoader loader)throws Exception {if( System.getSecurityManager() == null ){return;}loadCorePackage(loader);//加载org.apache.catalina.core.下的classloadCoyotePackage(loader);//加载org.apache.coyote下的classloadLoaderPackage(loader);loadRealmPackage(loader);loadSessionPackage(loader);loadUtilPackage(loader);loadValvesPackage(loader);loadJavaxPackage(loader);loadConnectorPackage(loader);loadTomcatPackage(loader);}
Bootstrap.load()
Bootstrap.load最终调用的是Catalina的load方法.
,主要完成:
- 设置系统变量
- 初始化命名系统
- Digester类,默认将conf/server.xml解析成相应的对象,这个解析很重要,因为是他完成了Connector和Container的初始化工作。
- Server调用init初始化声明周期,其父类LifecycleMBeanBase实现
//org.apache.catalina.startup.Catalina
private void load() {//当前面代码没有初始化CATALINA_BASE和CATALINA_HOME时,重新设置二者值initDirs();//初始化命名系统,即向System.Properties设置"java.naming.factory.initial"为"org.apache.naming.java.javaURLContextFactory"initNaming();//创建Digester,主要用于处理xml配置文件,创建Server,初始化Connector和ContainerDigester digester = createStartDigester();InputSource inputSource = null;InputStream inputStream = null;File file = null;try {//获取配置文件:默认值conf/server.xml,可由command参数-config指定file = configFile();inputStream = new FileInputStream(file);inputSource = new InputSource(file.toURI().toURL().toString());} //省略log,catch...//省略log,try-catch,部分代码.....try{inputSource.setByteStream(inputStream);digester.push(this);//解析xmldigester.parse(inputSource);} //省略log,catch...getServer().setCatalina(this);//System.out , System.errorinitStreams();//调用LifecycleBase.init();最终调用自身的initInternal()方法,见后续`StandardServer`getServer().init();
}
Digester解析server.xml
解析过程见: Tomcat—-Container源码分析StandardServer.init()初始化流程见: Tomcat—-生命周期管理
Boostrap.start()
最终调用的是Catalina.start()
,它主要完成:
- Server加载:Server才是正真的tomcat服务执行者。调用load方法,初始化Connector和Container
- 调用Server的start方法,最终调用的是StandardServer的startInternal方法,调用自己所有的Service的start方法,启动connector和container、excutor的start
- 注册钩子
//org.apache.catalina.startup.Catalina
public void start() {if (getServer() == null) {//Server加载load();}try {//服务启动,//调用LifecycleBase.start();最终调用自身的startInternal()方法getServer().start();} //省略 catch,log.....// 注册shutdown钩子if (useShutdownHook) {if (shutdownHook == null) {shutdownHook = new CatalinaShutdownHook();}Runtime.getRuntime().addShutdownHook(shutdownHook);LogManager logManager = LogManager.getLogManager();if (logManager instanceof ClassLoaderLogManager) {((ClassLoaderLogManager) logManager).setUseShutdownHook(false);}}//进入等待状态if (await) {//调用Server.await()方法await(); stop(); }}
至此,tomat就启动完成了。
Tomat启动-源码跟踪相关推荐
- spring-boot启动源码学习-1
2019独角兽企业重金招聘Python工程师标准>>> spring-boot启动源码分析-启动初始化 主要对spring-boot的启动流程中的启动初始化进行学习,学习spring ...
- 【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 二 )
文章目录 前言 一.热启动与冷启动选择 二.AMS 进程中执行的相关操作 三.通过 Binder 机制转到 ActivityThread 中执行的操作 总结 前言 上一篇博客 [Android 启动过 ...
- Android 9(P)之init进程启动源码分析指南之一
Android 9 之init进程启动源码分析指南之一 Android 9 (P) 系统启动及进程创建源码分析目录: Android 9 (P)之init进程启动源码分析指南之一 Andro ...
- Myth源码解析系列之五- 服务启动源码解析
通过前面几篇文章,我们搭建了环境,也进行了分布式事务服务的体验,相信大家对myth也有了一个大体直观的了解,接下来我们将正式步入源码解析之旅~~ order服务启动源码解析(myth-demo-spr ...
- spring-boot-2.0.3启动源码篇一 - SpringApplication构造方法
前言 spring-boot-2.0.3应用篇 - shiro集成,实现了spring-boot与shiro的整合,效果大家也看到了,工程确实集成了shiro的认证与授权功能.如果大家能正确搭建起来, ...
- 【Linux 内核 内存管理】Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
文章目录 一.ARM64 架构体系内存分布 二.Linux 内核启动源码 start_kernel 三.内存初始化源码 mm_init 四.内存初始化源码 mem_init 一.ARM64 架构体系内 ...
- 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )
文章目录 前言 一.ActivityManagerService.attachApplicationLocked 二.ActivityStackSupervisor.attachApplication ...
- 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 二 )
文章目录 前言 一.ActivityThread 类 handleLaunchActivity -> performLaunchActivity 方法 二.Instrumentation.new ...
- 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 一 )
文章目录 前言 一.ClientTransactionHandler.scheduleTransaction 二.ActivityThread.H 处理 EXECUTE_TRANSACTION 消息 ...
最新文章
- java 类的执行顺序_java类加载的顺序
- Elasticearch 安装 基础介绍 (一)
- 山东旅游学院2021高考成绩查询,2021年山东旅游职业学院录取查询入口,高考录取结果查询网址登录...
- 酒店管理系统c语言带注释,酒店管理系统--C语言版.pdf
- 如何使用IMPORT关键字读取ABAP cluster表里的数据到ABAP内表
- angularjs directive 实例 详解
- Redis作者antirez:开源维护者的挣扎
- 如何添加自动更新Play Framework 2.X项目的版本号
- 死锁Waiting--DeadLockDemo
- python数据挖掘分析案例python_Python 数据挖掘实例 决策树分析
- 深入理解MySQL8.0直方图
- iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄...
- python简明教程_04
- 自动跑程序vbs脚本
- 魔方口诀(个人备忘)
- 自定义xml解析框架
- 运动轨迹 php,两种JS实现小球抛物线轨迹运动的方法
- [问题已处理]-centos7 history命令没有任何记录
- 计算机本科生论文都抽查什么,本科生毕业论文抽查,抄袭马上会被撤销学位,学生最好别违规...
- dns 劫持什么意思、dns 劫持原理及几种解决方法