Tomcat的Catalina篇6-DefaultServlet和JspServlet

901 阅读3分钟

欢迎大家关注 github.com/hsfxuebao ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

Tomcat在$CATALINA_BASE/conf/web.xml中默认定义了两个Servlet:DefaultServlet和JspServlet,而且由于$CATALINA_BASE/conf/web.xml为Web应用的默认部署描述文件,因此这两个Servlet会默认存在于所有Web应用容器中。其具体配置如下:

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
        <param-name>fork</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>xpoweredBy</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
</servlet>

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

<!-- The mappings for the JSP servlet -->
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>

1. DefaultServlet

由前面的配置可知,DefaultServlet的url-pattern为“/”,因此,它将作为默认的Servlet。当客户端请求不能匹配其他所有Servleth时,将由该Servlet处理

DefaultServlet主要用于处理静态资源,如HTML、图片、CSS、JS文件等,而且为了提升服务器性能,Tomcat对访问文件进行了缓存。按照默认配置,客户端请求路径与资源的物理路径是一致的。即当我们输入的链接为http:/127.0.0.1:8080/myapp/static/sample.png时, 加载的图片物理路径为$CATALINA BASE/webapps/myapp/static/sample.png

当然,如果我们希望DefaultServlet只加载static目录下的资源,只需要将url-pattern改为“/static/*”即可(此时,DefaultServlet将不再是默认Servlet)。但是,这不会改变我们的请求路径,也就是说资源指向的仍旧是其物理路径,这是因为DefaultServlet根据完整的请求地址获取文件而非基于Servlet的相对路径。

如果我们希望Web应用覆盖Tomcat的DefaultServlet配置,只需要将“/”添加到自定义Servlet 的url-pattern中即可(此时,自定义Servlet将成为默认Servlet)。

  • 覆盖DefaultServlet配置时要慎重,因为这可能导致无法加载静态文件,除非在覆盖的情况下,自定义Servlet可以兼容DefaultServlet的功能以及对请求地址的处理(大多数Servlet基于相对路径来分发请求,而非完整路径。此时如果直接覆盖,将导致客户端请求无效)。

  • 当然,我们应该尽量避免使不同Servlet之间产生覆盖,因为覆盖结果会与具体的加载顺序(web.xml、web-fragment.xml以及注解顺序)相关,当系统复杂度上升时,可维护性势必会降低。建议通过划分Servlet请求目录(如:/static以、html/、js/等)指定请求扩展名(如:*.do、*action)来合理管理请求路径命名。

DefaultServlet除了支持访问静态资源,还支持查看目录列表,只需要将名为“listings”的init-param设置为true。此时如果我们输入http://127.0.0.1:8080/myapp/static/, 且该目录下没有任何欢迎文件(welcome-file-list配置),Tomcat将返回对应物理目录下的文件目录列表。

需要确保welcome-file-list不包含虚拟的文件名,如index.do,否则此时仍会由index.do匹 配的Servlet处理。

默认情况下,Tomcat以HTML的形式输出文件目录列表(包括文件名、大小、最后修改时间)。此外,可以通过参数 localXsltFi1e、contextXsltFile或globalXsltFile指定一个XSL或XSLT文件。此时,Tomcat将以XML形式输出文件目录,并使用指定的XSL或XSLT文件将其转换为响应输出。通过这种方式,我们可以根据需要定制文件目录输出界面。

Tomcat输出的XML内容格式如下:

<?xml version='1.0?>
<listing contextPath='web应用根目录'directory='当前查看目录'hasParent='true>
    <entries>
        <entry type='file'urlPath='文件路径'size='文件大小'date='最后修改时间'>文件名</entry>
        <entry type='dir'urlPath=:'子目录路径'date='最后修改时间'>目录名</entry>
    </entries>
</listing>

XSL及XSLT相关知识参见http:/www.w3.org/TR/xslt。

DefaultServlet支持的初始化参数如表所示,我们可以根据实际需要进行配置。

参数描述
debugDbug日志级别,主要用于开发环境。当前版本只有0、1~10、≥11这3个级别,而且同一级别内的值无论配置为何都是等价的
listings如果配置为tue,当请求目录下没有欢迎文件时,将显示文件目录列表,默认为false。如果目录下包含过多子目录和文件,该操作非常耗费性能,在请求访问量大的情况下占用大量系统资源
readmeFileReadMe文件名。当DefaultServlet允许显示文件目录,且当前文件目录下存在readmeFile指定的文件时,该文件将会被插入到最终的请求响应,以显示当前目录的ReadMe信息
globalXsltFileTomcat支持通过XSL定制文件目录显示列表,该参数用于指定XSL文件(基于CATALINABASE/confCATALINA_BASE/conf或CATALINA_HOME/conf的相对路径),因此XSL文件可以在所有Web应用中共享
contextXsltFile作用与globalXsltFi1e相同,但是文件路径相对于Wcb应用根目录,因此该参数指定的文件只用于具体的Web应用
localXsltFile作用与globalXs.1tFi1e相同,但是文件路径相对于当前请求目录,因此该参数指定的文件只适用于当前请求目录。Tomcat{优先使用该参数,其次为contextXsltFile,globalXs1tFi1e优先级最低
input读资源文件时,输人缓冲大小,单位为字节,默认为2048
output写资源文件时,输出缓冲大小,单位为字节,默认为2048
readonly如果配置为tue,Tomcat将会拒绝由DefaultServlet处理的PUT和DELETE请求
fileEncoding读取资源文件时使用的文件编码
sendfilesize如果当前连接器支持sendfile,该参数用于配置使用sendfile的最小文件大小,单位为KB。如果为负数,表示禁用sendfile
useAcceptRanges如果为true,将添加Accept--Rangesp响应头
showServerInfo如果为tue,将会在文件目录列表中输出服务器信息,当前版本只适用于默认格式输出的情况

2. JspServlet

默认情况下,JspServlet的url-pattern为*.jsp和*.jspx,因此它负责处理所有JSP文件的请求。

JspServlet主要完成以下工作。

  • 根据JSP文件生成对应Servlet的JAVA代码(JSP文件生成类的父类为org,apache.jasper.runtime.Http]spBase-一实现了Servlet接口)

  • 将JAVA代码编译为JAVA类。Tomcat支持Ant和JDT(Eclipse提供的编译器)两种方式编译JSP类,默认采用JDT。

  • 构造Servlet类实例并执行请求。

Tomcat默认配置的JspServlet,不仅用于处理SP文件,还用于配置指向单文件的Servlet。单文件的Servlet示例如下:

<servlet>
    <servlet-name>sample</servlet-name>
    <jsp-file>/sample/index.jsp</jsp-file>
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>sample</servlet-name>
    <url-pattern>*.x</url-pattern>
</servlet-mapping>

我们并没有指定servlet-class,而是增加了jsp-file,使其指向一个JSP文件。该Servlet处理所有扩展名为“*x”的请求

Tomcat如果指定了jsp-file,会自动将servlet-class设置为JspServlet,并将默认JspServlet中设置的初始化参数添加到当前Servlet。

参考文章

tomcat-9.0.60-src源码解析 
Tomcat架构解析