Tomcat9如何加载server.xml

技术Tomcat9如何加载server.xml小编给大家分享一下Tomcat9如何加载server.xml,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了

边肖将与您分享Tomcat9如何加载server.xml我相信大多数人还不太了解它,所以分享这篇文章供您参考。希望你看完这篇文章会有很多收获。我们一起来看看吧!

1.Tomcat启动

org.apache.catalina.startup.Bootstrap.main(String args[])

publicationstativonmain(Stringgars[]){ 0

同步(DaemonLock){ 0

if(守护进程==null){ 0

bootstrapbootstrap=new bootstrap();

尝试{

bootstrap . init();//初始化类加载器

} catch(Throwablet){ 0

handleThrowable(t);

t . printstacktrace();

返回;

}

守护进程=引导;

}else{

Thread.currentThread()。setContextClassLoader(daemon . catalinaloader);

}

}

//根据不同的传入指令进行相应的处理。

不间断空格

;     try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }
            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
                if (null == daemon.getServer()) {
                    System.exit(1);
                }
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else if (command.equals("configtest")) {
                daemon.load(args);
                if (null == daemon.getServer()) {
                    System.exit(1);
                }
                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            if (t instanceof InvocationTargetException &&
                    t.getCause() != null) {
                t = t.getCause();
            }
            handleThrowable(t);
            t.printStackTrace();
            System.exit(1);
        }
    }

在main方法中主要为两部分逻辑:

  • 调用bootstrap.init()进行初始化

  • 根据传入不同的指令进行相应的处理,本文主要分析start指定,即服务启动。启动服务start主要调用了org.apache.catalina.startup.Catalina.load()和start()方法

org.apache.catalina.startup.Bootstrap.init()
 public void init() throws Exception {
        initClassLoaders(); //初始化类加载
        Thread.currentThread().setContextClassLoader(catalinaLoader); //设置当前线程的类加载器为catalinaLoader
        SecurityClassLoad.securityClassLoad(catalinaLoader); //启用java安全管理的处理
        //通过反射的方式实例化org.apache.catalina.startup.Catalina,并设置父类加载器为sharedLoader
        if (log.isDebugEnabled())
            log.debug("Loading startup class");
        Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.getConstructor().newInstance();
        if (log.isDebugEnabled())
            log.debug("Setting startup class properties");
        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;
    }
  • 类加载器的初始化,创建commonLoader、catalinaLoader、sharedLoader,具体可参考上一篇
    《Tomcat9源代码浅析-类加载体系》

  • 启用java安全管理的处理

  • 通过反射的方式实例化org.apache.catalina.startup.Catalina,并设置父类加载器为sharedLoader

org.apache.catalina.security.SecurityClassLoad
public final class SecurityClassLoad {
    public static void securityClassLoad(ClassLoader loader) throws Exception {
        securityClassLoad(loader, true);
    }
    static void securityClassLoad(ClassLoader loader, boolean requireSecurityManager) throws Exception {
        if (requireSecurityManager && System.getSecurityManager() == null) {
            return;
        }
        loadCorePackage(loader);
        loadCoyotePackage(loader);
        loadLoaderPackage(loader);
        loadRealmPackage(loader);
        loadServletsPackage(loader);
        loadSessionPackage(loader);
        loadUtilPackage(loader);
        loadJavaxPackage(loader);
        loadConnectorPackage(loader);
        loadTomcatPackage(loader);
    }

当时使用Java SecurityManager时,会提前加载一些必要的java类,以避免触发权限异常AccessControlException

2.server.xml解析框架

2.1 SAX

Tomcat中使用SAX解析server.xml文件。SAX解析方式会逐行的解析XML文档,当遇到标签时会触发解析处理器,采用事件处理的方式解析XML,它的优点是不需要将完整的XML文档加载进内存,可以在读取文档的同时就进行解析,节省内存,适合解析超大XML,主要方法有:

  • startDocument():文档解析开始时调用,该方法只会调用一次

  • startElement(String uri, String localName, String qName, Attributes attributes):标签解析开始时调用

  • endElement(String uri, String localName, String qName):标签(节点)解析结束后调用

  • endDocument():文档解析结束后调用,该方法只会调用一次

2.2 规则Rules

Tomcat9如何加载server.xml
Tomcat将server.xml的解析抽象为规则,利用Java的引用传递,通过有副作用的void方法,对xml进行解析,规则调用的顺序与xml解析的顺序是一致的,即start方法是正序,end方法是逆序。
规则中包含以下方法:

  • begin:Degister.startElement 方法调用

  • body、end:Degister.endElement方法中调用,先调用body,再调用end

  • finish:Degister.endDocument方法中调用

Tomcat中常见的规则类型:

  • ObjectCreateRule 创建对应class的对象实例,并放到Designer的堆栈成员属性中

  • SetPropertiesRule 获取堆栈中栈顶的元素,并将xml元素的属性赋值给对象实例

  • SetNextRule 调用父节点的实例对象,将当前对象作为参数,反射调用某个方法

  • ListenerCreateRule 当Listener标签有optional属性为true时,创建实例异常时,强制添加OptionalListener实例

  • ConnectorCreateRule 创建Connector实例

  • SetAllPropertiesRule 主体功能与SetPropertiesRule 一致,这个Rule可以排除一些属性的设置

  • AddPortOffsetRule Set portOffset on all the connectors based on portOffset in the Server

  • CertificateCreateRule 实例化SSLHostConfigCertificate

3.server.xml解析源代码解析

org.apache.catalina.startup.Catalina.load()
public void load() {
        if (loaded) {
            return;
        }
        loaded = true;
        long t1 = System.nanoTime();
        initDirs();
        // Before digester - it may be needed
        initNaming();
        // 读取conf/server.xml
        ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
        File file = configFile();
        // 创建xml解析Digester 
        Digester digester = createStartDigester();
        try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
            InputStream inputStream = resource.getInputStream();
            InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
            inputSource.setByteStream(inputStream);
            digester.push(this);
            digester.parse(inputSource); //解析xml
        } catch (Exception e) {
            log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);
            if (file.exists() && !file.canRead()) {
                log.warn(sm.getString("catalina.incorrectPermissions"));
            }
            return;
        }
        //设置server的属性
        getServer().setCatalina(this);
        getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
        getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
        // Stream redirection
        initStreams();
        // 初始化server
        try {
            getServer().init();
        } catch (LifecycleException e) {
            if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                throw new java.lang.Error(e);
            } else {
                log.error(sm.getString("catalina.initError"), e);
            }
        }
        long t2 = System.nanoTime();
        if(log.isInfoEnabled()) {
            log.info(sm.getString("catalina.init", Long.valueOf((t2 - t1) / 1000000)));
        }
    }
  • Bootstrap中start指令逻辑,通过反射调用Catalina.load()

  • Catalina.load() 读取conf/server.xml,创建解析xml的Digester

  • 开始初始化server

org.apache.catalina.startup.Catalina.createStartDigester()
 protected Digester createStartDigester() {
        long t1=System.currentTimeMillis();
        // Initialize the digester
        Digester digester = new Digester();
        digester.setValidating(false);
        digester.setRulesValidation(true);
        Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
        // Ignore className on all elements
        List<String> objectAttrs = new ArrayList<>();
        objectAttrs.add("className");
        fakeAttributes.put(Object.class, objectAttrs);
        // Ignore attribute added by Eclipse for its internal tracking
        List<String> contextAttrs = new ArrayList<>();
        contextAttrs.add("source");
        fakeAttributes.put(StandardContext.class, contextAttrs);
        // Ignore Connector attribute used internally but set on Server
        List<String> connectorAttrs = new ArrayList<>();
        connectorAttrs.add("portOffset");
        fakeAttributes.put(Connector.class, connectorAttrs);
        digester.setFakeAttributes(fakeAttributes);
        digester.setUseContextClassLoader(true);
        // Configure the actions we will be using
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");
        digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResourcesImpl");
        digester.addSetProperties("Server/GlobalNamingResources");
        digester.addSetNext("Server/GlobalNamingResources",
                            "setGlobalNamingResources",
                            "org.apache.catalina.deploy.NamingResourcesImpl");
        digester.addRule("Server/Listener",
                new ListenerCreateRule(null, "className"));
        digester.addSetProperties("Server/Listener");
        digester.addSetNext("Server/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");
        digester.addObjectCreate("Server/Service/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Listener");
        digester.addSetNext("Server/Service/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        //Executor
        digester.addObjectCreate("Server/Service/Executor",
                         "org.apache.catalina.core.StandardThreadExecutor",
                         "className");
        digester.addSetProperties("Server/Service/Executor");
        digester.addSetNext("Server/Service/Executor",
                            "addExecutor",
                            "org.apache.catalina.Executor");
        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
        digester.addRule("Server/Service/Connector", new SetAllPropertiesRule(
                new String[]{"executor", "sslImplementationName", "protocol"}));
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.connector.Connector");
        digester.addRule("Server/Service/Connector", new AddPortOffsetRule());
        digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
                                 "org.apache.tomcat.util.net.SSLHostConfig");
        digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
        digester.addSetNext("Server/Service/Connector/SSLHostConfig",
                "addSslHostConfig",
                "org.apache.tomcat.util.net.SSLHostConfig");
        digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
                         new CertificateCreateRule());
        digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
                         new SetAllPropertiesRule(new String[]{"type"}));
        digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
                            "addCertificate",
                            "org.apache.tomcat.util.net.SSLHostConfigCertificate");
        digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
                                 "org.apache.tomcat.util.net.openssl.OpenSSLConf");
        digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
        digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
                            "setOpenSslConf",
                            "org.apache.tomcat.util.net.openssl.OpenSSLConf");
        digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
                                 "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
        digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
        digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
                            "addCmd",
                            "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
        digester.addObjectCreate("Server/Service/Connector/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Connector/Listener");
        digester.addSetNext("Server/Service/Connector/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
                                  null, // MUST be specified in the element
                                  "className");
        digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
        digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
                            "addUpgradeProtocol",
                            "org.apache.coyote.UpgradeProtocol");
        // Add RuleSets for nested elements
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
        // When the 'engine' is found, set the parentClassLoader.
        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader));
        addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
        long t2=System.currentTimeMillis();
        if (log.isDebugEnabled()) {
            log.debug("Digester for server.xml created " + ( t2-t1 ));
        }
        return digester;
    }

此方法创建解析server.xml的Digester,根据server.xml的元素标签,为每个标签设置相应的规则组,在解析标签时进行调用。
由此也可以得到结论,server.xml的结构就是Tomcat容器内部的结构,通过对server.xml的解析规则的执行,实例化出Tomcat容器结构。

以下为Tomcat9默认的server.xml

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

其结构见下图:
Tomcat9如何加载server.xml

  • Server代表服务器,一个Tomcat只有一个Server

  • Service 代表服务: 一个Server可以对外提供多个服务

  • Connector连接器: service服务的核心组成之一,主要是链接客户端请求

  • Container容器:service服务的核心组成之一,主要是执行业务逻辑,这里按层级为Engine、Host、Context

  • Wrapper:对应Servlet的定义
    Tomcat9如何加载server.xml

以上是“Tomcat9如何加载server.xml”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/138375.html

(0)

相关推荐

  • Python线性回归分析

    技术Python线性回归分析这篇文章主要介绍“Python线性回归分析”,在日常操作中,相信很多人在Python线性回归分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python线性回

    攻略 2021年11月9日
  • 抖音刷赞平台推广软件,抖音刷赞软件是真是假

    技术抖音刷赞平台推广软件,抖音刷赞软件是真是假抖音刷粉丝分三个步骤:1.选择抖音刷粉丝通道,2.准备刷粉丝账号,3.选择需要的套餐下订单刷粉,4.解释刷粉原理和方法。
    抖音粉丝最重要的就是选择一个可靠可靠的渠道,一家好的

    测评 2021年11月9日
  • 金箍棒怎么画,孙悟空怎么画,好看的)

    技术金箍棒怎么画,孙悟空怎么画,好看的)一、在画板的中央画出一个倒3字,然后再用一段弧形连接起来画出孙悟空的脸部金箍棒怎么画。二、接下来再画四个小圆圈,按照下图的方法画出孙悟空的眼睛。
    三、接下来我们再画出孙悟空的后脑勺

    生活 2021年10月31日
  • 巍怎么读,王巍导演的动画片好看吗

    技术巍怎么读,王巍导演的动画片好看吗执导了超过15,000分钟的动画片,包括巍怎么读:全国首部三维长篇动画系列《猪猪侠》(1-4部)《超兽武装之仁者无敌》、《超兽武装之勇者无惧》全国首部变形机器人系列《百变机兽》、
    Q版

    生活 2021年10月26日
  • d13-接口和内部类

    技术d13-接口和内部类 d13-接口和内部类## 1.接口
    ### 1.1黑马信息管理系统集合改进 (应用)
    + 使用数组容器的弊端1. 容器长度是固定的,不能根据添加功能自动增长 2. 没有提供用

    礼包 2021年11月22日
  • oracle表优化方法教程

    技术oracle表优化方法教程这篇文章主要讲解了“oracle表优化方法教程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“oracle表优化方法教程”吧!1、建立实验表c

    攻略 2021年11月11日