文章插图
image.png
Tomcat的启动核心流程 前面给大家介绍了Tomcat中的生命周期的设计,掌握了这块对于我们分析Tomcat的核心流程是非常有帮助的,也就是我们需要创建相关的核心组件,比如Server,Service肯定都绕不开生命周期的方法 。
文章插图
image.png
1.启动的入口 你可以通过脚本来启动Tomcat服务(startup.bat),但如果你看过脚本的命令,你会发现最终调用的还是Bootstrap中的main方法,所以我们需要从main方法来开始
文章插图
image.png
然后我们去看main方法中的代码,我们需要重点关注的方法有三个
- bootstrap.init()方法
- load()方法
- start()方法
2.init方法 我们来看下init方法中的代码,非核心的我们直接去掉
public void init() throws Exception {// 创建相关的类加载器initClassLoaders();// 省略部分代码...// 通过反射创建了 Catalina 类对象Class<?> startupClass = catalinaLoader.loadClass("org.Apache.catalina.startup.Catalina");// 创建了 Catalina 实例Object startupInstance = startupClass.getConstructor().newInstance();// 省略部分代码...String methodName = "setParentClassLoader";Class<?> paramTypes[] = new Class[1];paramTypes[0] = Class.forName("JAVA.lang.ClassLoader");Object paramValues[] = new Object[1];paramValues[0] = sharedLoader;// 把 sharedLoader 设置为了 commonLoader的父加载器Method method =startupInstance.getClass().getMethod(methodName, paramTypes);method.invoke(startupInstance, paramValues);// Catalina 实例 赋值给了 catalinaDaemoncatalinaDaemon = startupInstance;}
- 首先是调用了initClassLoaders()方法,这个方法会完成对应的ClassLoader的创建,这个比较重要,后面专门写一篇文章来介绍 。
- 通过反射的方式创建了Catalina的类对象,并通过反射创建了Catalina的实例
- 设置了类加载器的父子关系
- 用过成员变量catalinaDaemon记录了我们创建的Catalina实例
3.load方法 然后我们来看下load方法做了什么事情,代码如下:
private void load(String[] arguments) throws Exception {// Call the load() methodString methodName = "load"; // load方法的名称Object param[];Class<?> paramTypes[];if (arguments==null || arguments.length==0) {paramTypes = null;param = null;} else {paramTypes = new Class[1];paramTypes[0] = arguments.getClass();param = new Object[1];param[0] = arguments;}// catalinaDaemon 就是在 init中创建的 Catalina 对象Method method =catalinaDaemon.getClass().getMethod(methodName, paramTypes);if (log.isDebugEnabled()) {log.debug("Calling startup class " + method);}// 会执行 Catalina的load方法method.invoke(catalinaDaemon, param);}
上面的代码非常简单,通过注释我们也可以看出该方法的作用是调用 Catalina的load方法 。所以我们还需要加入到Catalina的load方法中来查看,代码同样比较长,只留下关键代码public void load() {if (loaded) {return; // 只能被加载一次}loaded = true;initDirs(); // 废弃的方法// Before digester - it may be neededinitNaming(); // 和JNDI 相关的内容 忽略// Create and execute our Digester// 创建并且执行我们的 Digester 对象Server.xmlDigester digester = createStartDigester();// 省略掉了 Digester文件处理的代码getServer().setCatalina(this); // Server对象绑定 Catalina对象getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());// Stream redirectioninitStreams();// 省略掉了部分代码...getServer().init(); // 完成 ServerService Engine Connector等组件的init操作}
把上面的代码简化后我们发现这个Load方法其实也是蛮简单的,就做了两件事 。- 通过Apache下的Digester组件完成了Server.xml文件的解析
- 通过getServer().init() 方法完成了Server,Service,Engin,Connector等核心组件的初始化操作,这块和前面的LifecycleBase呼应起来了 。
文章插图
推荐阅读
- 学习HTML5这一篇就够了
- 餐饮业|餐饮行业至暗时刻,居然还有人不知死活往里面冲?是的!第5篇
- SpringBoot内置Tomcat启动原理源码分析
- 局域网共享怎么设置都访问不了?别着急:一篇文章讲清了
- 穿衣搭配|看完这篇,职场少走五年弯路!!!
- 常用SQL语句,看这篇就够了
- 如何写出自己第一篇10万+文章?
- 服务器安全篇:最可怕的搜索引擎 运维必备之——Shodan
- MyBatis源码解析
- 职业教育|如花似玉就活该被当众踢脸踹头?2022年的第一桩丑闻就这样翻篇吗