拆解Tomcat10: (四) 图解架构(二)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 上一篇从Bootstrap类中的main方法开始了代码调试之旅,现在我们继续这个过程,看看Tomcat的核心组件架构。

3. 按配置创建核心组件

daemon.load(args)方法会调用Catalina类d的load(String args[])方法进行参数处理,进而调用load()方法,其代码如下:

/**
* 创建并初始化一个新的 server 实例.
*/
public void load() {
    if (loaded) {
        return;
    }
    loaded = true;
    long t1 = System.nanoTime();
    // 初始化Naming,因为在使用 digester解析server.xml时或许会被使用到
    initNaming();
    // 解析 server.xml
    parseServerXml(true);
    Server s = getServer();
    if (s == null) {
        return;
    }
    //将当前对象(catalinaDaemon)赋值给新创建的Server的catalina属性
    getServer().setCatalina(this);
    //将Bootstrap类中初始化的CatalinaHome和CatalinaBase赋值给Server的对应属性
    getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
    getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
    // Stream 重定向
    initStreams();
    // 初始化新的Server
    try {
        getServer().init();
    } catch (LifecycleException e) {
        if (throwOnInitFailure) {
            throw new java.lang.Error(e);
        } else {
            log.error(sm.getString("catalina.initError"), e);
        }
    }
    // 省略写日志的代码
}

3.1 initNaming()方法

用于设置附加的环境变量的值。主要涉及key为javax.naming.Context.URL_PKG_PREFIXES和javax.naming.Context.INITIAL_CONTEXT_FACTORY的两个变量。通过调用System.setProperty方法设置这两个Key对应的值。


javax.naming.Context.URL_PKG_PREFIXES

该常量的值为“java.naming.factory.url.pkgs”。它对应的Property值应该是一个以冒号分隔的包前缀列表,用于创建 URL 上下文工厂的工厂类的类名。


在initNaming()方法中,将"org.apache.naming"添加到冒号分隔的列表中。


javax.naming.Context.INITIAL_CONTEXT_FACTORY

保存环境属性名称的常量,用于指定要使用的初始上下文工厂。 该属性的值应该是将创建初始上下文的工厂类的完全限定类名。 该属性可以在传递给初始上下文构造函数的环境参数、系统属性或应用程序资源文件中指定。


在initNaming()方法中,将"org.apache.naming.java.javaURLContextFactory"设置为此Key的值。


3.2 parseServerXml方法

此方法的作用是解析Server.xml文件,


采用的解析工具为Digester。方法里有两个出现非常多的变量generateCode和useGeneratedCode:


generateCode:从配置文件生成Tomcat内嵌代码。

useGeneratedCode:使用生成的代码替代配置文件。

这两个变量可以在启动的时候通过main方法的args参数设置,默认状态下都是false,删掉相关代码,精简后的代码如下:

protected void parseServerXml(boolean start) {
    // 设置对应的配置文件  即Server.xml
    ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
    File file = configFile();
    File serverXmlLocation = null;
    String xmlClassName = null;
    ServerXml serverXml = null;
    if (serverXml != null) {
        serverXml.load(this);
    } else {
        try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
            // 创建并执行 Digester
            // createStartDigester 配置解析规则
            Digester digester = start ? createStartDigester() : createStopDigester();
            InputStream inputStream = resource.getInputStream();
            InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
            inputSource.setByteStream(inputStream);
            // 设置当前catalina对象为root节点
            digester.push(this);
            digester.parse(inputSource);
        } catch (Exception e) {
            log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);
            if (file.exists() && !file.canRead()) {
                log.warn(sm.getString("catalina.incorrectPermissions"));
            }
        }
    }
}

大概处理流程总结如下:


A. 设置并读取Server文件。

B. 创建Digester,并调用createStartDigester()方法设置解析规则。

注意:设置解析规则的时候,指定了各个XML节点对应的接口的实现类,截取部分createStartDigester()方法中的代码如下

// server节点
digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");
digester.addSetProperties("Server");
digester.addSetNext("Server","setServer","org.apache.catalina.Server");
//service节点
digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");

实现类多以StandardXXX命名,例如StandardServer、StandardService、StandardThreadExecutor等。

关系图如下:

58.png

(图二)


C. 设置当前catalina对象为root节点。

D. 执行解析操作,此时会根据配置的规则,对应XML的节点创建对应的实现类的实例,注意此时只是执行了构造方法,未进行其他初始化操作。

3.3 Server的初始化

下一章继续进行getServer().init();方法的源码阅读,看一看都做了哪些操作,由图二所示,这些组件都实现Lifeycle接口,有什么想法?


目录
相关文章
|
4月前
|
设计模式 Java 应用服务中间件
Tomcat 架构原理解析到设计借鉴
Tomcat 架构原理解析到设计借鉴
274 0
|
4月前
|
设计模式 Java 应用服务中间件
Tomcat 架构原理解析到架构设计借鉴
Tomcat 架构原理解析到架构设计借鉴
133 0
|
4月前
|
安全 Java 应用服务中间件
阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等
分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。
|
4月前
|
设计模式 安全 Java
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
89 0
|
29天前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件
|
4月前
|
存储 负载均衡 NoSQL
【分布式技术架构】「Tomcat技术专题」 探索Tomcat集群架构原理和开发分析指南
【分布式技术架构】「Tomcat技术专题」 探索Tomcat集群架构原理和开发分析指南
114 1
|
4月前
|
缓存 负载均衡 应用服务中间件
【分布式技术专题】「分析Web服务器架构」Tomcat服务器的运行架构和LVS负载均衡的运行机制(修订版)
在本章内容中,我们将深入探讨 Tomcat 服务器的运行架构、LVS 负载均衡的运行机制以及 Cache 缓存机制,并提供相应的解决方案和指导。通过理解这些关键概念和机制,您将能够优化您的系统架构,提高性能和可扩展性。
268 4
【分布式技术专题】「分析Web服务器架构」Tomcat服务器的运行架构和LVS负载均衡的运行机制(修订版)
|
4月前
|
前端开发 Java 应用服务中间件
架构篇:Tomcat 高层组件构建一个商业帝国
架构篇:Tomcat 高层组件构建一个商业帝国
327 6
|
4月前
|
XML 应用服务中间件 数据格式
Tomcat - Tomcat套娃式架构与配置文件的对应关系解读
Tomcat - Tomcat套娃式架构与配置文件的对应关系解读
37 1
|
4月前
|
前端开发 Java 应用服务中间件
Tomcat 架构设计 25 年后依旧能打!我学到了什么?
Tomcat 架构设计 25 年后依旧能打!我学到了什么?
67 0