Tomcat8源码分析-启动流程-MapperListener启动

上一篇:Tomcat8源码分析-启动流程-start方法java

MapperListener启动主要完成了将资源(class目录、jar、servlet-mapping、welcome list)添加MappedHost下的ContextVersion的不一样Wrappers数组当中,以及将本身设置为该Engine及其下面是全部容器的ContainerListener与LifeCycleListener设计模式

完成上面的功能有什么做用喃???能够说过重要了,看到“servlet-mapping”就应该想到确定是与处理请求的时候相关的,没错,当Tomcat处理请求的时候就会根据path与上面处理造成的Wrappers数组进行匹配获得Servlet,并设置给StandardWrapperValve.StandardWrapper.servlet,最终才能调用到对应Servlet的方法。数组

看看源码app

StandardService部分jsp

protected void startInternal() throws LifecycleException {

        。。。。。省略其余代码。。。。。

        /** 很重要
         * 会完成以下资源的解析与加载
         * 1.将Context下的Wrapper(自定义的Servlet\defaultServlet\jspServlet\jspxServlet)进行分析,并最终拆分为ContextVersion的四个Wrapper数组,
         *   exactWrappers\wildcardWrappers\extensionWrappers\defaultWrapper,他们在Tomcat接收请求时被用做与path匹配,最终得
         *   到想要的Servlet
         * 2.将Context中的WebResource(里面包含了好比class目录、jar包添加到ContextVersion
         * 3.将welcome list配置添加到ContextVersion
         *
         */

        mapperListener.start();

        。。。。。省略其余代码。。。。。
    }

调用start方法(按照前面讲的模板方法设计模式套路),紧接着会按照Mapper.registerHost-Mapper.registerContext-Mapper.addContextVersion-Mapper.addWrappers-Mapper.-Mapper.addWrapper这个顺序进入到下面的源代码,在这里面就完成了默认Servlet和自定义Sevlet的Mapping规则加载,等候被使用。源码分析

protected void addWrapper(ContextVersion context, String path,
            Wrapper wrapper, boolean jspWildCard, boolean resourceOnly) {

        synchronized (context) {
            if (path.endsWith("/*")) {//以"/*"开始的path加入到通配符wrapper当中
                // Wildcard wrapper
                String name = path.substring(0, path.length() - 2);
                MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                        jspWildCard, resourceOnly);
                MappedWrapper[] oldWrappers = context.wildcardWrappers;
                MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1];
                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                    context.wildcardWrappers = newWrappers;
                    int slashCount = slashCount(newWrapper.name);
                    if (slashCount > context.nesting) {
                        context.nesting = slashCount;
                    }
                }
            } else if (path.startsWith("*.")) {//以"*."开始的path加入到后缀Wrapper当中
                // Extension wrapper
                String name = path.substring(2);
                MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                        jspWildCard, resourceOnly);
                MappedWrapper[] oldWrappers = context.extensionWrappers;
                MappedWrapper[] newWrappers =
                    new MappedWrapper[oldWrappers.length + 1];
                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                    context.extensionWrappers = newWrappers;
                }
            } else if (path.equals("/")) {//设置默认的DefaultMapper
                // Default wrapper
                MappedWrapper newWrapper = new MappedWrapper("", wrapper,
                        jspWildCard, resourceOnly);
                context.defaultWrapper = newWrapper;
            } else { //到这里都还没匹配到的就是精确Wrapper了
                // Exact wrapper
                final String name;
                if (path.length() == 0) {
                    // Special case for the Context Root mapping which is
                    // treated as an exact match
                    name = "/";
                } else {
                    name = path;
                }
                MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                        jspWildCard, resourceOnly);
                MappedWrapper[] oldWrappers = context.exactWrappers;
                MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1];
                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                    context.exactWrappers = newWrappers;
                }
            }
        }
    }

再来看看ContextVersion实例化的时候传的参数有哪些,这些参数就说明了它包含了那些资源.net

//将新生成的Context添加到Host的contextList当中。在这里也验证了一个Host能够有多个Context(一个应用)
        mapper.addContextVersion(host.getName(), host, contextPath,
                context.getWebappVersion(), context, welcomeFiles, resources,
                wrappers);

其中的resources就是WebResource,里面就是以前已经解析完成的目录与jar资源设计

 

再来看看ContextVersion在Debug时构造完成后几个关键属性中的值code

这张图看清楚了Tomcat启动以后有哪些Wrapper(也就是Servlet能够使用)blog

这张图再点进去看能够看到目录与jar相关信息

 

总结

MapperListener真的很重要,完成了很是核心的servlet-mapping的分析与加载,让处理请求的阶段能够找到对照表(4中Wrappers数组)进行匹配,从而可以正确的进行业务逻辑处理。

相关文章
相关标签/搜索