首页 > 其他 > 详细

DispatchServlet源码分析(一)

时间:2015-06-29 02:04:42      阅读:382      评论:0      收藏:0      [点我收藏+]

?

?

DispatcheServlet类图,我们根据其类图进行源码分析
bubuko.com,布布扣
?

GenericServlet?源码分析

?

/**
 * 定义一个通用的,协议无关的Servlet.如果需要编写一个在Web中使用的Http Severlet需要继承HttpServlet
 * GeneraicServlet实现了Servlet接口和ServletConfig接口。GenericServlet          *可以直接通过Servlet扩展,虽然这是比较常见的一种是继承特殊协议的子类,如HttpServlet 
 * GenericServlet使写Servlet变的更容易。它提供简单的版本的生命周期方法 init,destory和ServletCOnfig接口中的方法
 * GenericServlet同样实现了生命在ServeltContext接口中的log方法s
 */
public abstract class GenericServlet 
    implements Servlet, ServletConfig, java.io.Serializable
{
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);

    private transient ServletConfig config;
    

    /**
     *无参构造方法
     *
     */
    public GenericServlet() { }
    
    
    /**
     * 被servlet容器调用,用来指示一个servlet正在停止服务
     * 
     */
    public void destroy() {
    }
    
    
    /**
	 *  返回一个命名的初始化参数的字符串值,如果这个初始化参数不存在则返回null
     *   这个方法对从ServletConfig对象中获指定名称的参数的值提供了便利
     */ 
    public String getInitParameter(String name) {
	     //获取ServletConfig对象
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }
		// 从servletConfig中获取指定名称初始化参数值
        return sc.getInitParameter(name);
    }
    
    
   /**
    * 将所有参数名称作为一个Enumeration<String>返回。如果没有初始化参数则返回一个空的Enumration
    */
    public Enumeration<String> getInitParameterNames() {
		 //获取servletConfig对象
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }
		//获取参数名称的枚举
        return sc.getInitParameterNames();
    }   
     

    /**
	 * 获取一个ServletConfig对象
     */    
    public ServletConfig getServletConfig() {
	return config;
    }
 
    
    /**
     *返回一个servlet正在其中运行的ServletContext的引用
     *
     *
     */
    public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }
		
        return sc.getServletContext();
    }


    /**
     *返回一个关于serlvet信息,比如 *作者,版本以及版权等。默认情况下,这个方法返回一个空字符串。如果需要返回有意义的值需要重写这个方法
     *
     */    
    public String getServletInfo() {
	return "";
    }


    /**
     * 被Servlet容器调用,用来标示一个servlet正准备开始服务
     */
    public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
    }


    
    public void init() throws ServletException {

    }
    

    
    public void log(String msg) {
	getServletContext().log(getServletName() + ": "+ msg);
    }
   
   
    
    public void log(String message, Throwable t) {
	getServletContext().log(getServletName() + ": " + message, t);
    }
    
    
    /**
     * 被servlet容器调用,让一个servlet响应一个请求
	 * 这是一个抽象方法,所以子类比如HttpServlet必须重写这个方法
     */

    public abstract void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
    

    /**
     * 返回servlet实例的名称
     */
    public String getServletName() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletName();
    }
}

?HttpServlet?源码分析

/**
 *  提供了一个抽象类用来被继承创建一个Http servlet来使用一个web站点。
 * 一个HttpServlet的子类必须至少重写下述中的一个方法
 * doGet,如果servlet支持Http get请求
 * doPost,支持http post请求
 * doPut, 支持http put请求
 * doDelete 支持http delete请求
 * init 和destroy 来管理servlet声明周期资源
 * getServletInfo,servlet用来提供自身信息
 *  几乎没有理由去重写service方法。service方法处理标准的Http请求时通过将其分发给相应请求类型的处理方法。
 *  Servlet通常运行在多线程服务器上,所以必须注意一个servlet必须处理并发请求,同时谨慎地同步访问共享资源。
 *  共享资源包括内存数据例如 实例或类变量和外部对象如文件,数据库连接,网络连接
 *
 */

public abstract class HttpServlet extends GenericServlet
{
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";

    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";
    
    private static final String LSTRING_FILE =
        "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);
   
    
    /**
     *无参构造方法
     * 
     */

    public HttpServlet() { }
    

    /**
     * 服务器通过service方法调用处理一个Http的get请求
     * 重写这个方法支持get请求同时也自动支持Http Head请求。Head请求是一个响应中没有返回体,只有请求头部字段
     */

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }


    /**
     * 返回HttpServletRequest对象的最后修改时间
     */

    protected long getLastModified(HttpServletRequest req) {
        return -1;
    }


   
    protected void doHead(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        NoBodyResponse response = new NoBodyResponse(resp);
        //委托给doGet方法
        doGet(req, response);
        response.setContentLength();
    }


    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }


    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_put_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }


    
    protected void doDelete(HttpServletRequest req,
                            HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_delete_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }
    

    private Method[] getAllDeclaredMethods(Class<?> c) {

        if (c.equals(javax.servlet.http.HttpServlet.class)) {
            return null;
        }

        Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
        Method[] thisMethods = c.getDeclaredMethods();
        
        if ((parentMethods != null) && (parentMethods.length > 0)) {
            Method[] allMethods =
                new Method[parentMethods.length + thisMethods.length];
            System.arraycopy(parentMethods, 0, allMethods, 0,
                             parentMethods.length);
            System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
                             thisMethods.length);

            thisMethods = allMethods;
        }

        return thisMethods;
    }




    /**
	 * 从公开的service方法中接收标准的HTTP请求,将其分发给相应的处理方法。
     */
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
		// 获取请求方法
        String method = req.getMethod();
		// 如果是get方法
        if (method.equals(METHOD_GET)) {
		   //获取最后修改时间
            long lastModified = getLastModified(req);
			// 如果最后修改时间未知
            if (lastModified == -1) {
			//分发给doGet方法处理
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
				// 如果servlet最后修改时间小于请求的最后修改时间则调用doGet,否则返回304
                if (ifModifiedSince < lastModified) {
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
				
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //没有支持的处理方法,返回一个错误响应
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
    

    /*
     * Sets the Last-Modified entity header field, if it has not
     * already been set and if the value is meaningful.  Called before
     * doGet, to ensure that headers are set before response data is
     * written.  A subclass might have set this header already, so we
     * check.
     */
    private void maybeSetLastModified(HttpServletResponse resp,
                                      long lastModified) {
        if (resp.containsHeader(HEADER_LASTMOD))
            return;
        if (lastModified >= 0)
            resp.setDateHeader(HEADER_LASTMOD, lastModified);
    }
   
    
    /**
     * 将请求委托给给protected void service(HttpServletRequest req, HttpServletResponse resp)
     */
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;
        
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        service(request, response);
    }
}


}

?

?HttpServletBean

public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware {

	
	protected final Log logger = LogFactory.getLog(getClass());

	/** 
	 * 一组必须为这个servlet提供的配置参数
	 */
	private final Set<String> requiredProperties = new HashSet<String>();

	private Environment environment = new StandardServletEnvironment();


	/**
	 * 强制子类调用这个方法来指定属性,并且必须提供作为作为配置参数。这个方法应该在子类的构造方法中调用y
	 */
	protected final void addRequiredProperty(String property) {
		this.requiredProperties.add(property);
	}

	/**
	 * 映射配置参数到这个Servlet bean的书zing同时调用子类的初始化方法
	 */
	@Override
	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet ‘" + getServletName() + "‘");
		}

		// 使用初始化参数设置bean的属性
		try {
			//创建一个ServletConfigPropertyValues对象
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			//获取当前对象的BeanWrapper,使用JavaBean风格访问bean的属性
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			//创建一个ServletContextResourceLoader
			ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
			// 设置bw的属性编辑器
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
			//初始化当前对象的BeanWrapper
			initBeanWrapper(bw);
			//设置bean属性
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			logger.error("Failed to set bean properties on servlet ‘" + getServletName() + "‘", ex);
			throw ex;
		}

		//调用子类初始化方法
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet ‘" + getServletName() + "‘ configured successfully");
		}
	}

	/**
	 * 对初始化BeanWrapper,可以使用自定义属性编辑器
	 * 默认实现是一个空方法
	 */
	protected void initBeanWrapper(BeanWrapper bw) throws BeansException {
	}


	/**
	 *  重写方法,如果没有servletConfig 则返回null
	 */
	@Override
	public final String getServletName() {
		return (getServletConfig() != null ? getServletConfig().getServletName() : null);
	}

	
	@Override
	public final ServletContext getServletContext() {
		return (getServletConfig() != null ? getServletConfig().getServletContext() : null);
	}


	/**
	 *子类通过重写这个方法实现自定义的初始化,在这个方法调用之前,这个Servlet所有bean属性都已经设置好了
	 */
	protected void initServletBean() throws ServletException {
	}

	
	public void setEnvironment(Environment environment) {
		this.environment = environment;
	}


	/**
	 * 从的ServletConfig初始化参数创建PropertyValues。
	 */
	private static class ServletConfigPropertyValues extends MutablePropertyValues {

		/**
		 * 创建一个新的ServeltConfigPropertyValues
		 */
		public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
		    throws ServletException {
			//获取所有丢失的参数
			Set<String> missingProps = (requiredProperties != null && !requiredProperties.isEmpty()) ?
					new HashSet<String>(requiredProperties) : null;
			// 获取所有初始化参数名枚举
			Enumeration en = config.getInitParameterNames();
			//遍历所有初始化参数
			while (en.hasMoreElements()) {
				String property = (String) en.nextElement();
				Object value = config.getInitParameter(property);
				//添加到property数组中
				addPropertyValue(new PropertyValue(property, value));
				if (missingProps != null) {
					missingProps.remove(property);
				}
			}

			// 如果依然有丢失的属性则抛出异常
			if (missingProps != null && missingProps.size() > 0) {
				throw new ServletException(
				    "Initialization from ServletConfig for servlet ‘" + config.getServletName() +
				    "‘ failed; the following required properties were missing: " +
				    StringUtils.collectionToDelimitedString(missingProps, ", "));
			}
		}
	}

}

?

DispatchServlet源码分析(一)

原文:http://zhangwei-david.iteye.com/blog/2222609

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!