前面的章节讲述了Servlet和Filter,不说一下web.xml总感觉少点什么。

好多人都知道web项目要配置web.xml,没有web.xml,web工程就起不来,为什么呢?我跟大部分一样都从未静下心来去细细品味一下。、

web.xml,中文名为部署描述文件,该文件由servlet定义,是web应用的配置文件。

部署描述符文件和其他的XML文件一样,都要由一个XML头开始。

这个头需要声明使用的XML版本,以及该xml使用的字符编码。

DOCYTPE声明可以有,也可以没有,本人使用的maven创建的web工程中,web.xml中没有该部分。

而创建的html文件中则有该部分的声明,例如:<!doctype html>,只是声明该文档是个html。

在这个声明之后,需要指定管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义),该语法会识别你的web.xml填写的是否正确。

在web.xml中其顶层元素为web-app,web.XML元素不像HTML,他们大小写敏感。

下面用maven创建web工程的web.xml代码(web.xml中的成员暂不填写):

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

</web-app>

当一个web程序启动时,web容器(tomcat等)就会去读取web.xml文件。

有人会问为什么叫web.xml,不叫其它的,这个我是没办法解释的,例如猫为什么叫猫....谁知道呢?

至于web容器(tomcat之类)怎么去读取的web.xml,这个我还是能大概说一下。

当tomcat启动的时候,tomcat会获取Catalina等其他类的一些数据,并设置一些参数,这些参数供tomcat使用。

当我们将我们的web应用部署在tomcat上时,tomcat就会读取我们web.xml,读取web.xml的代码如下(截取一部分):

protected void webConfig() {
        ......
        WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
                context.getXmlValidation(), context.getXmlBlockExternal());

        Set<WebXml> defaults = new HashSet<>();
        defaults.add(getDefaultWebXmlFragment(webXmlParser));

        WebXml webXml = createWebXml();

        // Parse context level web.xml
        InputSource contextWebXml = getContextWebXmlSource(); // 读取/WEB-INF/web.xml
        if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) { // /WEB-INF/web.xml文件的内容解析到webXml里面
            ok = false;
        }

        ServletContext sContext = context.getServletContext();

        Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser); // 解析的是webFragment

        ......

        // Step 3. Look for ServletContainerInitializer implementations
        if (ok) {
            processServletContainerInitializers(); // 这个是解析继承ServletContainerInitializer类的配置,
        }

       ......
    }


上面的代码设定了去哪个路径下读取web.xml并解析,以及获取servletContext等。

由此可知web.xml为什么在web-INF目录下,tomcat是怎么读取web.xml的都进行了简单描述。

我不想讲太多,在这里我想说的是,你不需要深入了解这一块,但是要知道红色线标记的这一块。

如果你想学习更多的,请深入学习一下tomcat,当然也可以参考下面这个大神的博客。


大概说了web容器加载web.xml的过程,接下要说一下web.xml中常用到的成员。

1.schema

  web.xml的模式文件是由Sun公司定义的,每个web.xml文件的根元素<web-app>中,都必须标明这个 web.xml使用的是哪个模式文件。

其它的元素都放在<web-app></web-app>之中。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
</web-app>

2.<display-name>,Web应用的名称,用来标记这个特定的Web应用的一个名称

<display-name>Tomcat Example</display-name>

3.<context-param>,web应用上下文参数,声明应用范围内的初始化参数。

它用于向 ServletContext提供键值对,即应用程序上下文信息。我们的listener, filter等在初始化时会用到这些上下文中的信息。

在servlet里面可以通过getServletContext().getInitParameter("context/param")得到。

<context-param>
    <param-name>ContextParameter</para-name>
    <param-value>test</param-value>
</context-param>

4.<filter>过滤器,将自写的Filter过滤类,添加到web应用中,这个过滤类需要实现javaxs.servlet.Filter接口(具体可以看我前面的章节)

<filter>
    <filter-name>setCharacterEncoding</filter-name>
    <filter-class>com.abc.FilterA</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>setCharacterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

5.<listener>监听器

<listener> 
    <listerner-class>com.listener.SessionListener</listener-class> 
</listener>

6.<servlet>, 用来声明一个servlet的数据

<servlet-name></servlet-name> 指定servlet的名称

<servlet-class></servlet-class> 指定servlet的类名称

<jsp-file></jsp-file> 指定web站台中的某个JSP网页的完整路径

<init-param></init-param> 用来定义参数,可有多个init-param。在servlet类中通过getInitParamenter(String name)方法访问初始化参数

<load-on-startup></load-on-startup>指定当Web应用启动时,装载Servlet的次序。

当值为正数或零时:Servlet容器先加载数值小的servlet,再依次加载其他数值大的servlet。

当值为负或未定义:Servlet容器将在Web客户首次访问这个servlet时加载它。

<servlet-mapping></servlet-mapping> 用来定义servlet所对应的URL,包含两个子元素

<servlet-name></servlet-name> 指定servlet的名称

<url-pattern></url-pattern> 指定servlet所对应的URL


一般都用的是基本配置,高级配置可以忽略

<!-- 基本配置 -->
<servlet>
    <servlet-name>snoop</servlet-name>
    <servlet-class>SnoopServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>snoop</servlet-name>
    <url-pattern>/snoop</url-pattern>
</servlet-mapping>
<!-- 高级配置 -->
<servlet>
    <servlet-name>snoop</servlet-name>
    <servlet-class>SnoopServlet</servlet-class>
    <init-param>
        <param-name>foo</param-name>
        <param-value>bar</param-value>
    </init-param>
    <run-as>
        <description>Security role for anonymous access</description>
        <role-name>tomcat</role-name>
    </run-as>
</servlet>
<servlet-mapping>
    <servlet-name>snoop</servlet-name>
    <url-pattern>/snoop</url-pattern>
</servlet-mapping>

7.<session-config>会话超时配置,单位为分钟

<session-config>
    <session-timeout>120</session-timeout>
</session-config>

8.<welcome-file-list>欢迎文件页

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
</welcome-file-list>

9.<error-page>错误页面

<!-- 1、通过错误码来配置error-page。当系统发生×××错误时,跳转到错误处理页面。 -->
<error-page>
    <error-code>404</error-code>
    <location>/NotFound.jsp</location>
</error-page>
<!-- 2、通过异常的类型配置error-page。当系统发生java.lang.NullException(即空指针异常)时,跳转到错误处理页面。 -->
<error-page>
    <exception-type>java.lang.NullException</exception-type>
    <location>/error.jsp</location>
</error-page>

web.xml中的常用的基本成员都在上面了。

虽然大多数人已经学习了SSH,不看这一些东西,但是这些东西是真正的基础,搞不懂这些,SSH也就难以更上一层楼。

叙述过了Filter和Listener,也说过了Servlet,那就说一下web容器加载web.xml中成员的顺序:

web容器加载web项目时,会去读取web.xml。在web.xml中,他会读取listener,Filter,Context-param。

读取顺序:首先会读取context-param,再读取listener,读取完这两个,就会去创建ServletContext。

(在listener中,我曾说过,实现指定接口后的监听类可以监听application,即ServletContext。如果不读取Listener,那就没办法创建监听,即接下来对application的相关操作无从得知)

监听读取过了,被监听对象的参数也有了。现在创建被监听对象ServletContext。(被监听对象由web容器创建),然后容器将被监听对象的参数传给监听对象(Context-param传给ServletContext),接下来创建监听对象(listener),在实现的监听对象中,我们可以通过监听对象获得已经创建的ServletContext,以及Context-param参数。
因为ServletContext是当前web项目共享的,所以它比所有的servlet创建的都要早,既然ServletContext比Servlet的创建早,那么对Context-param做相关操作也必然比servlet的创建要早。

由此得知:web.xml中会先读取Context-param,然后是listener,再读取Filter。

Filter因为可以过滤用户对某个Servlet的请求,所以,应该在创建Servlet前被创建。

由此,我们得知:context-param -> listener -> filter -> servlet

另外,web.xml中的成员顺序不影响web容器对其的读取顺序,毕竟取值的时候按key-value读取的。