(5.1) Tomcat 8 源码, 实例化组件

25 篇文章 0 订阅
3 篇文章 0 订阅

上一章:  初始化 bootstrap.init()

https://blog.csdn.net/weixin_42209307/article/details/108580214   

 

我们回到, org.apache.catalina.startup.Bootstrap#main 方法

daemon.load(args) , daemon 就是我们的bootstrap实例, 在这个里面就会解析server.xml 并且创建各个组件的实例,

并且一层一层向下, 初始化组件

我们这节只分享组件实例化, 下一节分享, 组件的初始化

// Bootstrap.java
public static void main(String args[]) {

        // ....
        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);
       // ...
    }

    
    // Bootstrap.java
    private void load(String[] arguments) throws Exception {

        // Call the load() method
        String methodName = "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;
        }
        Method method =
            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        if (log.isDebugEnabled()) {
            log.debug("Calling startup class " + method);
        }
        method.invoke(catalinaDaemon, param);
    }

可以看到是 bootstrap 还是不自己干活, 正如它的翻译, 它只是引导, 它只做了两件事

  1. 获取Catalina 的 load 方法的反射
  2. 执行方法

org.apache.catalina.startup.Catalina#load() 

// Catalina.java
public void load() {

        // 防止重入
        if (loaded) {
            return;
        }
        loaded = true;

        // 开始时间
        long t1 = System.nanoTime();

        // 啥也没干, 这个方法是废弃的
        initDirs();

        // 初始化命名空间, 向内存中添加一下些静态变量, 这个想看的可以自己DEBUG 进去看
        initNaming();

        // XML 解析器, 我们重点讲这个
        Digester digester = createStartDigester();

        InputSource inputSource = null;
        InputStream inputStream = null;
        File file = null;
        try {
            try {
                // 获取server.xml 配置
                file = configFile();
                inputStream = new FileInputStream(file);
                inputSource = new InputSource(file.toURI().toURL().toString());
            } catch (Exception e) {
                if (log.isDebugEnabled()) {
                    log.debug(sm.getString("catalina.configFail", file), e);
                }
            }

            //...代码省略

            // 这里就是去拿默认的server.xml 配置
            if (inputStream == null) {
                try {
                    inputStream = getClass().getClassLoader()
                            .getResourceAsStream("server-embed.xml");
                    inputSource = new InputSource
                    (getClass().getClassLoader()
                            .getResource("server-embed.xml").toString());
                } catch (Exception e) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("catalina.configFail",
                                "server-embed.xml"), e);
                    }
                }
            }


            //...代码省略

            try {
                inputSource.setByteStream(inputStream);
                // 将Catalina 对象提供给解析器, 创建的实例都会放到Catalina里面去, 并且设置Root节点
                digester.push(this);
                // 开始解析, 并且创建对象, 这个我们就不往下跟了, 等有时间, 带各位看看, 因为规则大家都知道了, xml是怎么被解析的, 解析标签以后又该干嘛
                digester.parse(inputSource);
            } catch (SAXParseException spe) {
                log.warn("Catalina.start using " + getConfigFile() + ": " +
                        spe.getMessage());
                return;
            } catch (Exception e) {
                log.warn("Catalina.start using " + getConfigFile() + ": " , e);
                return;
            }
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }

        // 这个后面的代码我们下一次再讲, 一步一步慢慢的分析tomcat

        // 设置server 的 servlet(Catalina) 容器, 就是Bootstrap中的, 同一个对象, 所以到这里就可以知道, servlet 容器是全局存在的, 同一个实例, 因为server 只有一个
        getServer().setCatalina(this);
        // -Dcatalina.home=catalina-home
        getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
        // -Dcatalina.base=catalina-home
        getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());

        // 初始化console 打印, 
        initStreams();

        // 初始化server <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("Catalina.start", e);
            }
        }

        // 结束时间
        long t2 = System.nanoTime();
        if(log.isInfoEnabled()) {
            log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
        }
    }

下面就是我们的本节重点了, 组件是怎么实例化的

 Digester digester = createStartDigester();


    // Catalina.java
    protected Digester createStartDigester() {
        long t1=System.currentTimeMillis();
        // 创建一个解析器对象
        Digester digester = new Digester();
        // 是否校验
        digester.setValidating(false);
        // 是否校验xml规则
        digester.setRulesValidation(true);
        Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
        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);
        digester.setFakeAttributes(fakeAttributes);
        // 是否使用上下文类加载器, 这个类加载器就是在bootstrap.init(), 设置的上下文 sharedLoader
        digester.setUseContextClassLoader(true);

        // 我们解读这一块代码, 本文全部都是在为这个做铺垫
        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.addObjectCreate("Server/Listener",
                                 null, // MUST be specified in the element
                                 "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"}));
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.connector.Connector");

        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 标签解析, 这个里面的解析都是SAX解析, 一行一行的来的, 消耗内存小

Server 标签

        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");
  1.  digester.addObjectCreate  创建一个解析节点,解析谁呢?
    1. param1:节点名称 Server
    2. param2:解析完以后实例化什么, 这里配置看一个全路径类名
    3. param3:它是什么类型, className, 类名称嘛, 这个很明显就是可以实例化的
  2. digester.addSetProperties 节点名称和Server对应
  3. digester.addSetNext           创建完以后干嘛,干嘛呢
    1. param1:对应节点
    2. param2:调用的函数  setServer
    3. param3:传参类型  
  • 流程就是, 解析节点创建实例 -> 创建实例完成以后放置在那里
  • 我们主要看 digester.addSetNext 的第二个参数 , setServer 这个函数在那呢??
  • 因为 Server 没有父节点, 所以它的父节点默认就是Root, Root 就是 Catalina,  这个在哪里可以验证?
// 这就是在解析前, 将Catalina设置进去了
// Digester.java
public void push(Object object) {

        if (stack.size() == 0) {
            root = object;
        }
        stack.push(object);

}
  • 所以可以断定 setServer  是在 Catalina 里面, 事实也是如此
// Catalina.java
public void setServer(Server server) {
        this.server = server;
    }

Service 标签

  • service 标签和  server 标签大概一致
  • 只有digester.addObjectCreate 的一个参数可能大部分不是很懂 
  • Server/Service , 不仅表面的 xml 的节点关系, 还表面了父子关系
  • 所以这就是为什么 addService 这个在Catalina里面找不到, 因为它在 父组件 StandardServer 里面
    // org.apache.catalina.core.StandardServer#addService
    @Override
    public void addService(Service service) {

        service.setServer(this);

        synchronized (servicesLock) {
            Service results[] = new Service[services.length + 1];
            System.arraycopy(services, 0, results, 0, services.length);
            results[services.length] = service;
            services = results;

            if (getState().isAvailable()) {
                try {
                    service.start();
                } catch (LifecycleException e) {
                    // Ignore
                }
            }

            // Report this property change to interested listeners
            support.firePropertyChange("service", null, service);
        }

    }

到这里我们本章节的任务已经算是完成了,  各位有兴趣的可以去看 组件的默认构造器, 看在实例化的时候都做了些什么操作, 

这里我就不带大家去看了,   再以后的分析中,  自然会讲, 

下一步, 将带各位查看组件的初始化, 会涉及部分组件的构造器, 才明白是数据是怎么来的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值