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)

相关推荐

  • 怎么为SQL Server快照snapshot DB建立login访问

    技术怎么为SQL Server快照snapshot DB建立login访问这篇文章主要讲解了“怎么为SQL Server快照snapshot DB建立login访问”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟

    攻略 2021年11月9日
  • JS构造函数和实例化的关系及原型引入举例分析

    技术JS构造函数和实例化的关系及原型引入举例分析这篇文章主要介绍“JS构造函数和实例化的关系及原型引入举例分析”,在日常操作中,相信很多人在JS构造函数和实例化的关系及原型引入举例分析问题上存在疑惑,小编查阅了各式资料,

    攻略 2021年11月29日
  • 效用中内存分配策略的实例分析

    技术Utility中内存分配策略的示例分析这篇文章主要为大家展示了“Utility中内存分配策略的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Utility中内存分

    攻略 2021年12月22日
  • Bytom如何使用PAT树

    技术Bytom如何用PAT树本篇内容介绍了“Bytom如何用PAT树”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么

    攻略 2021年12月20日
  • 梅子金黄杏子肥下一句,梅子金黄杏子肥的下一句是什么

    技术梅子金黄杏子肥下一句,梅子金黄杏子肥的下一句是什么梅子金黄杏子肥的下一句是麦花雪白菜花稀梅子金黄杏子肥下一句。原诗为: 四时田园杂兴·其二——范成大 梅子金黄杏子肥,麦花雪白菜花稀。日长篱落无人过,惟有蜻蜓蛱蝶飞。解

    生活 2021年10月26日
  • 橘去掉木念什么,橘子去掉木字旁加一个鸟子念什么

    技术橘去掉木念什么,橘子去掉木字旁加一个鸟子念什么读音:[yù]鹬的繁体字“鷸”一种鸟,羽毛茶褐色,嘴橘去掉木念什么、脚都很长,趾间无蹼,常在水边或田野中捕吃小鱼、小虫和贝类。鹬聚、蛎鹬、鹬冠、鹬子、鹬蚌鹬鹬、杓鹬属、鹬

    生活 2021年10月22日