写java web程序的人一定对web.xml很熟悉。但却不知道它的具体含义,比如spring集成时,配置文件是什么意思。要想搞清楚,必须弄清楚原生的servlet api的知识。


1,servlet

Servlet可以看成是一次对请求的处理方式,类似于spring中的controller。在一个web应用中,会有很多的servlet,web应用容器会管理这些全部的servlet实例。在api中,servlet角色的行为被定义在了Servlet接口中:最主要的有inti()和service()方法。web容器要初始化一个servlet,要读取它的配置文件,配置信息有servletConfig接口处理。然后有一个GenericServlet同时实现了servlet和servletConfig接口,是所有servlet类的基类,不过它仅仅是将servletConfig的配置信息导入了,真正具有处理请求功能的servlet实现类是httpservlet,它继承自GenericServlet。它的service()方法是一个大的if,选择是get还是post等,真正的请求放在doget和dopost方法里面。我们自己写的servlet只要继承httpservlet即可,复写doget和dopost,不能复写service方法。

2,serlvetContext

这也是一个接口,它主要处理web应用的根环境,也就是整个应用的上下文,即所有serlvet实例的上下文,为不是具体的某一个servlet实例的上下文,这个可能有误解。查看它的api后发现,我们可以通过它得到application作用域的对象,以及初始化根上下文的参数和全部的servlet实例等等。总而言之它就是根上下文,管理全部的web应用相关的资源。web.xml文件其实就是servletcontext的初始化配置文件。

这样,在web应用刚启动的时候,会根据web.xml文件来初始化根上下文,包括全局的变量和各种servlet和listener等。

3,web.xml中的context-param参数

是根上下文的初始化参数,我们可以通过

getServletContext().getInitParameter(String name)
方法得到这些参数。助注意这个参数与application域内的参数不一样,它仅仅是初始化参数,并不在application域对象内。

4,servlet初始化参数

是servlet启动的参数,可以通过

getServletConfig().getInitParameter("name")
方法得到。

5,Listener:

Listener当然有很多,这里只说与servlet相关的。

ServletContextListener监听器用于监听servletcontext初始化和销毁。在serlvetcontext初始化之后和销毁之前处理一下逻辑。

相应的处理函数:

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		
		
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		
		
	}
也就是说当servletcontext创建好之后,会调用contextInitialized()方法。

实现了监听器类后要在web.xml 文件中注册。


下面结合具体实例说明:

web.xml:

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

    <context-param>
       <param-name>c</param-name>
       <param-value>lzy</param-value>
    </context-param>
    <!-- 配置spring核心servlet -->    
    <servlet>    
        <servlet-name>a</servlet-name>    
        <servlet-class>com.test.HelloServlet</servlet-class>  
        <init-param>
           <param-name>name</param-name>
           <param-value>ly</param-value>
        </init-param> 
    </servlet>    
    <servlet-mapping>    
        <servlet-name>a</servlet-name>    
        <url-pattern>/hello.view</url-pattern>    
    </servlet-mapping>    
    
    <listener>
        <listener-class>com.test.ContextParamListener</listener-class>
    </listener>
</web-app> 
配置了根上下文的初始化参数和一个servlet(及servlet的初始化参数)

listener:

package com.test;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ContextParamListener implements ServletContextListener{

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		
		String param = sce.getServletContext().getInitParameter("c");
		sce.getServletContext().setAttribute("p", param);
		
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		// TODO Auto-generated method stub
		
	}

}
这个监听器读取了servletcontext的初始化参数,并且赋值到application域对象中,名字为p,这样servlet中就可以访问到新的参数了。


Servlet:

package com.test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response){
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter writer;
		try {
			writer = response.getWriter();
			writer.write("hello");
			writer.close();
			
			System.out.println(getServletConfig().getInitParameter("name"));
			System.out.println(getServletContext().getInitParameter("c"));
			
			System.out.println(getServletContext().getAttribute("p"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
运行结果:

web.xml与listener_java

小结:

context-param是web根上下文的初始化参数

init-param是servlet的初始化参数
listener监听器会被web容器在发生相应的事件时调用(观察者模式)


再看spring:

这样看来,spring就是用spring自身提供的一个servletcontextlistener的实现,根据context-param来读取配置文件,初始化自己的bean容器。当然这个容器是在根上下文内。spring mvc是一个特殊的servlet,原本servlet用来转发不同的请求,springmvc用一个servlet处理全部的请求,将这些请求转发到不同的controller。