Tomcat9如何加载server.xml

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

成都创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:网站制作、成都网站制作、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的饶河网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

1.Tomcat启动

org.apache.catalina.startup.Bootstrap.main(String args[])
 public static void main(String args[]) {
        synchronized (daemonLock) {
            if (daemon == null) {
                Bootstrap bootstrap = new Bootstrap();
                try {
                    bootstrap.init(); //初始化类加载器
                } catch (Throwable t) {
                    handleThrowable(t);
                    t.printStackTrace();
                    return;
                }
                daemon = bootstrap;
            } 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, List> fakeAttributes = new HashMap<>();
        // Ignore className on all elements
        List objectAttrs = new ArrayList<>();
        objectAttrs.add("className");
        fakeAttributes.put(Object.class, objectAttrs);
        // Ignore attribute added by Eclipse for its internal tracking
        List contextAttrs = new ArrayList<>();
        contextAttrs.add("source");
        fakeAttributes.put(StandardContext.class, contextAttrs);
        // Ignore Connector attribute used internally but set on Server
        List 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



  
  
  
  
  
  
    
  
  
    
    
    
      
        
        
      
      
        
      
    
  

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

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

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

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

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

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

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


当前题目:Tomcat9如何加载server.xml
标题链接:http://scyanting.com/article/poseog.html