tomcat的url-pattern的源码分析

1 静态文件的处理前言分析

最近想把SpringMVC对于静态资源的处理策略弄清楚,如它和普通的请求有什么区别吗?

有人可能就要说了,现在有些静态资源都不是交给这些框架来处理,而是直接交给容器来处理,这样更加高效。我想说的是,虽然是这样,处理静态资源也是MVC框架应该提供的功能,而不是依靠外界。

这里以tomcat容器中的SpringMVC项目为例。整个静态资源的访问,效果图如下:

可以分成如下2个大的过程

  • tomcat根据url-pattern选择servlet的过程
  • SpringMVC对静态资源的处理过程(这个留到下一篇文章来详细的源码说明)

2 tomcat的处理策略

这里要看tomcat的源码,所以pom中加入相应依赖,使debug的时候能够定位到源码文件,目前我所使用的tomcat版本为7.0.55,你要是使用的不同版本,则更换下对应依赖的版本就行

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-catalina</artifactId>
    <version>7.0.55</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-coyote</artifactId>
    <version>7.0.55</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper</artifactId>
    <version>7.0.55</version>
    <scope>provided</scope>
</dependency>

2.1 tomcat默认注册的servlet

tomcat默认注册了,映射 ‘/‘ 路径的的DefaultServlet,映射.jsp和.jspx的JspServlet,这些内容配置在tomcat的conf/web.xml文件中,如下:

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
</servlet>

<servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>
  • DefaultServlet可以用来处理tomcat一些资源文件
  • JspServlet则用来处理一些jsp文件,对这些jsp文件进行一些翻译

我们可以修改此配置文件,来添加或者删除一些默认的servlet配置。

下面来看下这些servlet的url-pattern的规则是什么样的

2.2 servlet的url-pattern的规则

对于servlet的url-pattern规则,这里也有一篇对应的源码分析文章tomcat的url-pattern源码分析

2.2.1 tomcat源码中的几个概念

在分析之前简单看下tomcat源码中的几个概念,Context、Wrapper、Servlet:

  • Servlet 这个很清楚,就是继承了HttpServlet,用户用它的service方法来处理请求
  • Wrapper 则是Servlet和映射的结合,具体点就是web.xml中配置的servlet信息
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
  • Context 表示一个应用,包含了web.xml中配置的所有信息,所以当一个请求到来时,它负责找到对应的Servlet,然后调用这个Servlet的service方法,执行我们所写的业务逻辑。

Context把上述的根据映射寻找Servlet的过程封装起来交给了一个org.apache.tomcat.util.http.mapper.Mapper类来完成,所以请求匹配规则都在这个Mapper中来完成。

所以这个Mapper做了2件事情

  • 在初始化web.xml的时候,Mapper需要收集其中的servlet及其映射信息并进行一定的处理,存储到Mapper的内部类ContextVersion中
  • 在请求到来的时候,它能根据请求地址,选择出对应的servlet等信息,供使用

Mapper的内部类ContextVersion对映射对应的servlet进行了分类存储,如下:

protected static final class ContextVersion extends MapElement {
    public String[] welcomeResources = new String[0];
    public Wrapper defaultWrapper = null;
    public Wrapper[] exactWrappers = new Wrapper[0];
    public Wrapper[] wildcardWrappers = new Wrapper[0];
    public Wrapper[] extensionWrappers = new Wrapper[0];
    //略
}

总共分成了5种,分别是

  • welcomeResources 欢迎页面,就是web.xml中可以配置的如下内容,待会以案例的形式详细说明它的作用

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
    </welcome-file-list>
    
  • defaultWrapper 用于存放默认的servlet信息
  • exactWrappers 用于精确匹配,即要求必须一模一样
  • wildcardWrappers 用于通配符匹配 如 /*、/abc/*
  • extensionWrappers 用于扩展名匹配,即 .jsp、.html等

下面就来看看Mapper是如何进行归类处理的

2.2.2 Mapper的归类处理Servlet和映射信息

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

    synchronized (context) {
        if (path.endsWith("/*")) {
            // Wildcard wrapper
            String name = path.substring(0, path.length() - 2);
            Wrapper newWrapper = new Wrapper(name, wrapper, jspWildCard,
                    resourceOnly);
            Wrapper[] oldWrappers = context.wildcardWrappers;
            Wrapper[] newWrappers =
                new Wrapper[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("*.")) {
            // Extension wrapper
            String name = path.substring(2);
            Wrapper newWrapper = new Wrapper(name, wrapper, jspWildCard,
                    resourceOnly);
            Wrapper[] oldWrappers = context.extensionWrappers;
            Wrapper[] newWrappers =
                new Wrapper[oldWrappers.length + 1];
            if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                context.extensionWrappers = newWrappers;
            }
        } else if (path.equals("/")) {
            // Default wrapper
            Wrapper newWrapper = new Wrapper("", wrapper, jspWildCard,
                    resourceOnly);
            context.defaultWrapper = newWrapper;
        } else {
            // 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;
            }
            Wrapper newWrapper = new Wrapper(name, wrapper, jspWildCard,
                    resourceOnly);
            Wrapper[] oldWrappers = context.exactWrappers;
            Wrapper[] newWrappers =
                new Wrapper[oldWrappers.length + 1];
            if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                context.exactWrappers = newWrappers;
            }
        }
    }
}

上面几个if else语句就解释的很清楚

  • 以 /* 结尾的,都纳入通配符匹配,存到ContextVersion的wildcardWrappers中
  • 以 *.开始的,都纳入扩展名匹配中,存到ContextVersion的extensionWrappers中
  • / ,作为默认的,存到ContextVersion的defaultWrapper中
  • 其他的都作为精准匹配,存到ContextVersion的exactWrappers中

此时我们可能会想,url形式多样,也不会仅仅只有这几种吧。如/a/*.jsp,即不是以 /* 结尾,也不是以 *. 开始,貌似只能分配到精准匹配中去了,这又不太合理吧。实际上tomcat就把url形式限制死了,它会进行相应的检查,如下

private boolean validateURLPattern(String urlPattern) {

    if (urlPattern == null)
        return (false);
    if (urlPattern.indexOf(‘\n‘) >= 0 || urlPattern.indexOf(‘\r‘) >= 0) {
        return (false);
    }
    if (urlPattern.equals("")) {
        return true;
    }
    if (urlPattern.startsWith("*.")) {
        if (urlPattern.indexOf(‘/‘) < 0) {
            checkUnusualURLPattern(urlPattern);
            return (true);
        } else
            return (false);
    }
    if ( (urlPattern.startsWith("/")) &&
            (urlPattern.indexOf("*.") < 0)) {
        checkUnusualURLPattern(urlPattern);
        return (true);
    } else
        return (false);

}

显然,urlPattern可以为”“,其他必须以 *. 或者 / 开头,并且两者不能同时存在。/a/*.jsp不符合最后一个条件,直接报错,tomcat启动失败,所以我们不用过多的担心servlet标签中的url-pattern的复杂性。

初始化归类完成之后,当请求到来时,就需要利用已归类好的数据进行匹配了,找到合适的Servlet来响应

2.2.3 Mapper匹配请求对应的Servlet

在Mapper的internalMapWrapper方法中,存在着匹配规则,如下

private final void internalMapWrapper(ContextVersion contextVersion,
                                      CharChunk path,
                                      MappingData mappingData)
    throws Exception {
    //略
    // Rule 1 -- Exact Match
    Wrapper[] exactWrappers = contextVersion.exactWrappers;
    internalMapExactWrapper(exactWrappers, path, mappingData);

    // Rule 2 -- Prefix Match
    boolean checkJspWelcomeFiles = false;
    Wrapper[] wildcardWrappers = contextVersion.wildcardWrappers;
    if (mappingData.wrapper == null) {
        internalMapWildcardWrapper(wildcardWrappers, contextVersion.nesting,
                                   path, mappingData);
        //略
    }
    //略
    // Rule 3 -- Extension Match
    Wrapper[] extensionWrappers = contextVersion.extensionWrappers;
    if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
        internalMapExtensionWrapper(extensionWrappers, path, mappingData,
                true);
    }

    // Rule 4 -- Welcome resources processing for servlets
    if (mappingData.wrapper == null) {
        boolean checkWelcomeFiles = checkJspWelcomeFiles;
        //略
    }
    //略
    // Rule 7 -- Default servlet
    if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
        if (contextVersion.defaultWrapper != null) {
            mappingData.wrapper = contextVersion.defaultWrapper.object;
            mappingData.requestPath.setChars
                (path.getBuffer(), path.getStart(), path.getLength());
            mappingData.wrapperPath.setChars
                (path.getBuffer(), path.getStart(), path.getLength());
        }
       //略
    }
    //略
}

长长的匹配规则,有兴趣的可以去仔细研究下,对于Welcome resources匹配,下文会举2个例子来详细的分析其规则,其他的我们仅仅了解下大概的匹配顺序就可以了,匹配顺序如下:

  • (1) 首先精准匹配
  • (2) 然后是通配符匹配
  • (3) 然后是扩展名匹配
  • (4) 然后是欢迎页面匹配(这里又细分了很多的规则,下面的案例分析会详细说明)
  • (5) 最后是默认匹配

3 案例分析(结合源码)

在说明案例之前,需要先将eclipse中的tomcat信息说明白,有时候修改tomcat配置没起作用就是因为你修改的地方不对导致的

3.1 前提:eclipse中tomcat的配置信息

  • 新建的tomcat server,是将你所安装的tomcat的配置进行复制后,存放在当前eclipse所在工作空间路径的server项目下,如下:

所以以后要修改所使用的tomcat信息,就直接在该项目下修改,或者直接去该项目的路径下,直接修改对应的配置文件

  • 新建的tomcat server的运行环境不是你所安装的tomcat的webapps目录下,而是在当前eclipse所在的工作空间的.metadata文件下,具体如下: .metadata\.plugins\org.eclipse.wst.server.core ,这个目录下会有一个或多个tmp目录,每个tmp目录都对应着一个tomcat的真实运行环境,然后找到那个你所使用的tmp目录,你就会看到如下的信息

这里的wtwebapps就是tomcat默认的发布根目录,这个是不固定的,可配置的。

3.2 jsp的访问案例

举个简单例子:tomcat的根路径下有一个a.jsp文件,就是上述的tomcat发布的根目录,在这个根目录中,我们放一个jsp文件,文件内容如下:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
    <h1>JSP Page</h1>
        Hello ${param.name}!
    </body>
</html>

默认情况下,即JspServlet存在,访问 http://localhost:8080/a.jsp?name=lg ,结果如下:

如果你修改了tomcat的默认配置,去掉JspServlet的话,同样访问 http://localhost:8080/a.jsp?name=lg ,结果如下

这时候就,没有了JspServlet,不会进行相应的翻译工作,而是使用DefaultServlet直接将该文件内容进行返回。

因为tomcat默认配置了,映射 / 的DefaultServlet和映射 *.jsp 的JspServlet。在初始化web.xml的时候,上文讲的Mapper类按照归类规则,DefaultServlet作为了默认的servlet,JspServlet作为了扩展名的servlet,它比DefaultServlet的级别高,执行了扩展名匹配,所以返回了翻译后的jsp的内容。当去掉JspServlet时,使用了DefaultServlet,执行了默认匹配,此时的jsp文件仅仅是一个一般的资源文件,返回了jsp的原始内容。

3.3 welcome-file-list案例

它是具有两种作用的,作为项目的主页和作为跳转的阶梯,下面先介绍两个案例,然后根据源码分析其原因。

注意点: 我把项目的根目录作为tomcat的发布的目录,所以访问 http://localhost:8080/ 中不再加入项目名

3.3.1 作为项目的主页

  • 案例1:在项目的根路径下,放置一个a.html文件,FirstServlet拦截 /first/,SecondServlet拦截 .action,web.xml中是如下配置

    <servlet>
        <servlet-name>first</servlet-name>
        <servlet-class>com.lg.servlet.FirstServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>first</servlet-name>
        <url-pattern>/first/*</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>second</servlet-name>
        <servlet-class>com.lg.servlet.SecondServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>second</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>a.html</welcome-file>
    </welcome-file-list>
    

    这时,我们访问 http://localhost:8080/ 即想访问项目的主页,就能访问到a.html的内容,如下:

  • 案例2:对welcome-file-list稍加修改,其他不变,如下
    <welcome-file-list>
        <welcome-file>a.jsp</welcome-file>
    </welcome-file-list>
    

    在根目录下再存放一个a.jsp文件,如下:

    <%@page contentType="text/html"%>
    <%@page pageEncoding="UTF-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
       "http://www.w3.org/TR/html4/loose.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>JSP Page</title>
        </head>
        <body>
        <h1>JSP Page</h1>
            Hello ${param.name}!
        </body>
    </html>
    

    访问 http://localhost:8080/ 结果返回的是

    可以得出表面结论: 就是tomcat会根据不同的扩展名,使用相应的servlet来解析文件,然后返回

3.3.2 作为跳转的阶梯

  • 案例3:对welcome-file-list再次修改如下,其他不变:

    <welcome-file-list>
        <welcome-file>a.action</welcome-file>
    </welcome-file-list>
    

    这里又可以分2种情况,即根目录下是否存在a.action,然而无论哪种情况,访问http://localhost:8080/,在本案例中都会返回上文配置的SecondServlet的内容(然而他们的执行逻辑却是不一样的),返回内容如下:

  • 案例4:同理,再次修改welcome-file-list如下,访问http://localhost:8080/,就可以访问到上文配置的FirstServlet的内容:
    <welcome-file-list>
        <welcome-file>first/abc</welcome-file>
    </welcome-file-list>
    

3.3.3 源码解释

下面我们就来根据源码分析分析整个是什么样的过程,这一部分详细的源码如下:

// Rule 4 -- Welcome resources processing for servlets
if (mappingData.wrapper == null) {
    boolean checkWelcomeFiles = checkJspWelcomeFiles;
    if (!checkWelcomeFiles) {
        char[] buf = path.getBuffer();
        checkWelcomeFiles = (buf[pathEnd - 1] == ‘/‘);
    }
    if (checkWelcomeFiles) {
        for (int i = 0; (i < contextVersion.welcomeResources.length)
                 && (mappingData.wrapper == null); i++) {
            path.setOffset(pathOffset);
            path.setEnd(pathEnd);
            path.append(contextVersion.welcomeResources[i], 0,
                    contextVersion.welcomeResources[i].length());
            path.setOffset(servletPath);

            // Rule 4a -- Welcome resources processing for exact macth
            internalMapExactWrapper(exactWrappers, path, mappingData);

            // Rule 4b -- Welcome resources processing for prefix match
            if (mappingData.wrapper == null) {
                internalMapWildcardWrapper
                    (wildcardWrappers, contextVersion.nesting,
                     path, mappingData);
            }

            // Rule 4c -- Welcome resources processing
            //            for physical folder
            if (mappingData.wrapper == null
                && contextVersion.resources != null) {
                Object file = null;
                String pathStr = path.toString();
                try {
                    file = contextVersion.resources.lookup(pathStr);
                } catch(NamingException nex) {
                    // Swallow not found, since this is normal
                }
                if (file != null && !(file instanceof DirContext) ) {
                    internalMapExtensionWrapper(extensionWrappers, path,
                                                mappingData, true);
                    if (mappingData.wrapper == null
                        && contextVersion.defaultWrapper != null) {
                        mappingData.wrapper =
                            contextVersion.defaultWrapper.object;
                        mappingData.requestPath.setChars
                            (path.getBuffer(), path.getStart(),
                             path.getLength());
                        mappingData.wrapperPath.setChars
                            (path.getBuffer(), path.getStart(),
                             path.getLength());
                        mappingData.requestPath.setString(pathStr);
                        mappingData.wrapperPath.setString(pathStr);
                    }
                }
            }
        }

        path.setOffset(servletPath);
        path.setEnd(pathEnd);
    }

}
// Rule 4d --我暂且叫它 Rule 4d (源码并没有这样写)
if (mappingData.wrapper == null) {
    boolean checkWelcomeFiles = checkJspWelcomeFiles;
    if (!checkWelcomeFiles) {
        char[] buf = path.getBuffer();
        checkWelcomeFiles = (buf[pathEnd - 1] == ‘/‘);
    }
    if (checkWelcomeFiles) {
        for (int i = 0; (i < contextVersion.welcomeResources.length)
                 && (mappingData.wrapper == null); i++) {
            path.setOffset(pathOffset);
            path.setEnd(pathEnd);
            path.append(contextVersion.welcomeResources[i], 0,
                        contextVersion.welcomeResources[i].length());
            path.setOffset(servletPath);
            internalMapExtensionWrapper(extensionWrappers, path,
                                        mappingData, false);
        }

        path.setOffset(servletPath);
        path.setEnd(pathEnd);
    }
}

从上面可以看到,其中的path不再是原来的path,而是我们的访问path+welcome-file中配置的路径,作为全新的路径,对于欢迎资源,又细分了4中规则,分别如下:

  • 4a: 对全新的路径进行精准匹配
  • 4b: 对全新的路径进行通配符匹配
  • 4c: 根据全新的路径,进行查找是否存在相应的文件,如果存在相应的文件,则需要将该文件返回。在返回前我们需要进一步确认,这个文件是不是讲文件内容源码返回,还是像jsp文件一样,进行一定的处理然后再返回,所以又要确认下文件的扩展名是怎样的
    • 4c1: 尝试寻找能够处理该文件扩展名的servlet,即进行扩展名匹配,如果找到,则使用对应的servlet
    • 4c2: 如果没找到,则默认使用defaultWrapper,即DefaultServlet(它只会将文件内容源码返回,不做任何处理)
  • 4d: 对全新的路径进行扩展名匹配(与4c的目的不同,4c的主要目的是想返回一个文件的内容,在返回内容前涉及到扩展名匹配,所以4c的前提是存在对应路径的文件)

有了以上的规则,我们就来详细看看上文的4个案例都是走的哪个规则

  • 案例1: a.html,4a、4b没有匹配到,到4c的时候,找到了该文件,然后又尝试扩展名匹配,来决定是走4c1还是4c2,由于.html还没有对应的servlet来处理,就使用了默认的DefaultServlet
  • 案例2: a.jsp,同上,在走到4c的时候,找到了处理.jsp对应的servlet,所以走了4c1
  • 案例3: a.action,如果根目录下有a.action文件,则走到4c1的时候,进行扩展名匹配,匹配到了SecondServlet,即走了4c1,使用SecondServlet来处理请求;如果根目录下没有a.action文件,则走到了4d,进行扩展名匹配,同样匹配到了SecondServlet,即走了4d,同样使用SecondServlet来处理请求
  • 案例4: first/abc,执行4b的时候,就匹配到了FirstServlet,所以使用FirstServlet来处理请求

至此,就把welcome-file-list彻底讲清楚了,有什么问题和疑问,欢迎提问

4 结束语

了解了tomcat的url-pattern的规则后,下一篇文章就要说明SpringMVC是如何来处理静态资源的,以及他们的综合分析。

时间: 2024-08-11 06:57:34

tomcat的url-pattern的源码分析的相关文章

Tomcat源码分析——请求原理分析(中)

前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原理分析(上)>一文中的相关知识以及HTTP协议和TCP协议的一些内容.本文重点讲解Tomcat7.0在准备好接受请求后,请求过程的原理分析. 请求处理架构 在正式开始之前,我们先来看看图1中的Tomcat请求处理架构. 图1 Tomcat请求处理架构 图1列出了Tomcat请求处理架构中的主要组件,这里

Tomcat源码分析——server.xml文件的加载与解析

前言 作为Java程序员,对于tomcat的server.xml想必都不陌生.本文基于Tomcat7.0的Java源码,对server.xml文件是如何加载和解析进行分析. 加载过程分析 Bootstrap的load方法用于加载tomcat的server.xml,实际是通过反射调用Catalina的load方法,代码如下: /** * Load daemon. */ private void load(String[] arguments) throws Exception { // Call

Tomcat源码分析 (八)----- HTTP请求处理过程(一)

终于进行到Connector的分析阶段了,这也是Tomcat里面最复杂的一块功能了.Connector中文名为连接器,既然是连接器,它肯定会连接某些东西,连接些什么呢? Connector用于接受请求并将请求封装成Request和Response,然后交给Container进行处理,Container处理完之后再交给Connector返回给客户端. 要理解Connector,我们需要问自己4个问题. (1)Connector如何接受请求的? (2)如何将请求封装成Request和Response

tomcat源码分析前的准备工作

Tomcat源码学习前的准备工作 注:由于网上的帖子大部分没有配套的图片和错误的分析,所有费了半天劲整理了此篇博客,希望大家少走弯路吧 下面我们就开始我们的Tomcat源码学习之旅. 1. 下载Tomcat6.0的源代码 首先,我们得下载Tomcat6.0的源代码.Tomcat源代码的版本控制工具不是CVS,而是Subversion,如果您的机器上没有安装Subversion,请从http://subversion.tigris.org/servlets/ProjectDocumentList?

【MyBatis】MyBatis Tomcat JNDI原理及源码分析

一. Tomcat JNDI JNDI(java nameing and drectory interface),是一组在Java应用中访问命名和服务的API,所谓命名服务,即将对象和名称联系起来,使得可以通过名称访问并获取对象. 简单原理介绍:点击访问 tomcat已经集成该服务(内置并默认使用DBCP连接池),简单来说就是键值对的mapping,而且在tomcat服务器启动的首页configuration中就已经有完成的示例代码.要想使用tomcat的JNDI服务,只需要导入相关的jar包,

Tomcat源码分析——server.xml文件的加载

前言 作为Java程序员,对于tomcat的server.xml想必都不陌生.本文基于Tomcat7.0的Java源码,对server.xml文件是如何加载的进行分析. 源码分析 Bootstrap的load方法是加载tomcat的server.xml的入口,load方法实际通过反射调用了Catalina的load方法,见代码清单1. 代码清单1 /** * Load daemon. */ private void load(String[] arguments) throws Exceptio

Tomcat源码分析

前言: 本文是我阅读了TOMCAT源码后的一些心得. 主要是讲解TOMCAT的系统框架, 以及启动流程.若有错漏之处,敬请批评指教! 建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的. 所以得实践.实践.再实践. 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动过程. 如果有不明白的地方, 再来查阅本文, 看是否能得到帮助. 我相信这样效果以及学习速度都会好很多! 1. Tomcat的整体框架结构 Tomcat的基本框架,

Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]

前言 今天研究了一下tomcat上web.xml配置文件中url-pattern的问题. 这个问题其实毕业前就困扰着我,当时忙于找工作. 找到工作之后一直忙,也就没时间顾虑这个问题了. 说到底还是自己懒了,没花时间来研究. 今天看了tomcat的部分源码 了解了这个url-pattern的机制.  下面让我一一道来. tomcat的大致结构就不说了, 毕竟自己也不是特别熟悉. 有兴趣的同学请自行查看相关资料. 等有时间了我会来补充这部分的知识的. 想要了解url-pattern的大致配置必须了解

Tomcat源码分析——类加载体系

前言 Tomcat遵循J2EE规范,实现了Web容器.很多有关web的书籍和文章都离不开对Tomcat的分析,初学者可以从Tomcat的实现对J2EE有更深入的了解.此外,Tomcat还根据Java虚拟机规范实现了经典的双亲委派模式的类加载体系.本文基于Tomcat7.0的Java源码,对其类加载体系进行分析. 概述 本节简单介绍Java虚拟机规范中提到的主要类加载器: Bootstrap Loader:加载lib目录下或者System.getProperty(“sun.boot.class.p