zoukankan      html  css  js  c++  java
  • DispatchServlet源码分析

    DispatcheServlet类图,我们根据其类图进行源码分析

     



     

     

    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正准备开始服务。在该方法中将
    *    * ServletConfig赋值给属性config后调用init()方法
         */
        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, ", "));
    			}
    		}
    	}
    
    }
    

     FrameworkServlet

    /**
     * Spring's web框架的Servlet基类。提供在一个基于JavaBean集成Spring应用上下文的解决方案
     * 这个类提供了如下功能:
     *  管理每个Servlet的WebApplicationContext实例。servlet的配置servlet命名空间中的bean由决定
     *  发布请求处理事件,不论请求是否被成功处理 publishEvents=true,默认为true
     *  子类必须实现doService方法去处理请求。因为这个类继承HttpeServletBean类而不是直接继承HttpServlet类,
     *  子类可以重写initFrameworkServlet来自定义初始化
     *  在servlet初始化参数中检测contextClass并将其设置为默认的上下文类,如果没有找到则使用XmlWEbApplicationContext.一般都是使用默认值
     *  注意,默认情况下自定义的上下文类需要实现ConfigurableWebApplicationContext接口。 
     *  接受一个可选参的servelt初始化参数contextInitializerClassers指定一个或多个ApplicationContextInitializer;托管的WebApplicationContext会
     *  委托给这些指定的初始化器增加一些额外的程序化配置。
     *  ContextLoader也支持具有相同语义的contextInitializerClassers上线文参数,对根上下文进行程序化配置。
     *  传递servlet初始化配置参数contextConfigLocation到上下文中,解析成潜在可以通过逗号空格分割的多文件路径,
     *  例如“test-servlet.xml,myServlet.xml”
     *  如果没有明确指明contextConfigLocation,则从servlet命名空间中加载默认的路径的配置文件
     *  需要注意的是:在配置多个路径时,后面Bean中定义将覆盖前一个加载文件中的配置,至少Spring默认ApplicationContext实现是这么处理的。
     *  默认的命名空间是servletName-servlet,例如test-servlet, servlet的名称就是test,
     *  XmlWebApplication默认的加载路径是/WEB-INF/test-servlet.xml
     *  
     */
    @SuppressWarnings("serial")
    public abstract class FrameworkServlet extends HttpServletBean {
    
    	/**
    	 * *WebApplicationContext命名空间的后缀。如果一个servlet在这个类的上下文中给定的名字是“test”,这个servlet的命名空间则使**用test-servelt
    	 */
    	public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
    
    	/**
    	 *FrameworkServlet默认的上下文
    	 */
    	public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
    
    	/**
    	 * WebApplicationContext在servlet 上下文中属性名称的前缀。最后.
    	 */
    	public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";
    
    	/**
    	 * 在一个初始化参数的多个值之间使用分割符分割
    	 * 
    	 */
    	private static final String INIT_PARAM_DELIMITERS = ",; 	
    ";
    
    
    	/**  */
    	private String contextAttribute;
    
    	/** WebApplicationContext实现类 */
    	private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
    
    	/** WebApplicationContext的Id*/
    	private String contextId;
    
    	/** 当前servlet的命名空间 */
    	private String namespace;
    
    	/** 上下文配置路径 */
    	private String contextConfigLocation;
    
    	/** 是否将WebApplicationContext发布为Servlet上下文的一个属性。默认是true */
    	private boolean publishContext = true;
    
    	/**  是否在每个请求结束发布一个ServletRequestHandledEvent */
    	private boolean publishEvents = true;
    
    	/** Expose LocaleContext and RequestAttributes as inheritable for child threads? */
    	private boolean threadContextInheritable = false;
    
    	/** 是否分发Http opetion请求 */
    	private boolean dispatchOptionsRequest = false;
    
    	/** 是否分发http trace请求 */
    	private boolean dispatchTraceRequest = false;
    
    	/**当前servlet的WebApplicationContext */
    	private WebApplicationContext webApplicationContext;
    
    	/** 标志onFreash方法是否已经被调用过*/
    	private boolean refreshEventReceived = false;
    
    	/** Comma-delimited ApplicationContextInitializer classnames set through init param */
    	private String contextInitializerClasses;
    
    	/** Actual ApplicationContextInitializer instances to apply to the context */
    	private ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =
    			new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
    
    
    
    	public FrameworkServlet() {
    	}
    
    	
    	public FrameworkServlet(WebApplicationContext webApplicationContext) {
    		this.webApplicationContext = webApplicationContext;
    	}
    
      // setter and getter
    
    	/**
    	 * 重写HttpServletBean的方法,在所有属性设置完成后调用,创建当前servlet的WebApplicationContext
    	 */
    	@Override
    	protected final void initServletBean() throws ServletException {
    	    //记录日志
    		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
    		if (this.logger.isInfoEnabled()) {
    			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
    		}
    		long startTime = System.currentTimeMillis();
    
    		try {
    			//初始化webApplicationContext
    			this.webApplicationContext = initWebApplicationContext();
    			//初始化FrameworkServlet
    			initFrameworkServlet();
    		}
    		catch (ServletException ex) {
    			this.logger.error("Context initialization failed", ex);
    			throw ex;
    		}
    		catch (RuntimeException ex) {
    			this.logger.error("Context initialization failed", ex);
    			throw ex;
    		}
    
    		if (this.logger.isInfoEnabled()) {
    			long elapsedTime = System.currentTimeMillis() - startTime;
    			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
    					elapsedTime + " ms");
    		}
    	}
    
    	/**
    	 * 初始化WebApplicationContext
    	 */
    	protected WebApplicationContext initWebApplicationContext() {
    	  //获取根WebApplicationContext
    		WebApplicationContext rootContext =
    				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    		WebApplicationContext wac = null;
    		// 如果一个上下文对象已经在构造方法中创建则直接使用
    		if (this.webApplicationContext != null) {
    			wac = this.webApplicationContext;
    				//如果web应用上下文是ConfiguableWebApplicontionContext
    			if (wac instanceof ConfigurableWebApplicationContext) {
    			  // 强制类型转换
    				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
    				  //如果上下文不是活跃的,即上线问没有被刷新
    				if (!cwac.isActive()) {
    					  // 如果没有父上下文对象,则将根上下文设置为父上下文
    					if (cwac.getParent() == null) {
    						cwac.setParent(rootContext);
    					}
    					//配置同时刷新上下文
    					configureAndRefreshWebApplicationContext(cwac);
    				}
    			}
    		}
    		//如果在构造方法中没有注入上下文,则在servlet上下文中找到一个已经注册的上下文。
    		if (wac == null) {
    			
    			wac = findWebApplicationContext();
    		}
    		if (wac == null) {
    		    // 如果当前servlet没有定义上下文对象则创建一个本地webApplicationContext
    			wac = createWebApplicationContext(rootContext);
    		}
            
    		if (!this.refreshEventReceived) {
    			 
    			onRefresh(wac);
    		}
    
    		if (this.publishContext) {
    		   //将上下文发布为一个servlet上下文属性
    		    // 获取属性名称
    			String attrName = getServletContextAttributeName();
    			//将其设置为servlet上下文的一个属性
    			getServletContext().setAttribute(attrName, wac);
    			if (this.logger.isDebugEnabled()) {
    				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
    						"' as ServletContext attribute with name [" + attrName + "]");
    			}
    		}
    
    		return wac;
    	}
    
    	/**
         * 
    	 */
    	protected WebApplicationContext findWebApplicationContext() {
    	     //获取上下文属性名称
    		String attrName = getContextAttribute();
    		// 如果属性名称为null则返回null
    		if (attrName == null) {
    			return null;
    		}
    		// 从servlet 上下文中获取Web应用上下文
    		WebApplicationContext wac =
    				WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
    		// 如果web应用上下文为null则抛出一个异常,否则返回这个上下文
    		if (wac == null) {
    			throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
    		}
    		return wac;
    	}
    
    	/**
    	 *穿件一个新的WebApplicaitonContext对象
    	 */
    	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
    		Class<?> contextClass = getContextClass();
    		if (this.logger.isDebugEnabled()) {
    			this.logger.debug("Servlet with name '" + getServletName() +
    					"' will try to create custom WebApplicationContext context of class '" +
    					contextClass.getName() + "'" + ", using parent context [" + parent + "]");
    		}
    		// 如果web应用上下文类不是ConfigurableWebApplicationContext类或其子类则抛出一个异常
    		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
    			throw new ApplicationContextException(
    					"Fatal initialization error in servlet with name '" + getServletName() +
    					"': custom WebApplicationContext class [" + contextClass.getName() +
    					"] is not of type ConfigurableWebApplicationContext");
    		}
    		// 创建一个ConfiguableWebApplicaitonContext对象
    		ConfigurableWebApplicationContext wac =
    				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    		// 设置父上下文
    		wac.setParent(parent);
    		//设置配置资源路径
    		wac.setConfigLocation(getContextConfigLocation());
    		// 刷新
    		configureAndRefreshWebApplicationContext(wac);
    		//返回上下文对象
    		return wac;
    	}
    
    	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
    			// 如果当前contextId不为null则将web应用上下文的Id设置为contextId
    			if (this.contextId != null) {
    				wac.setId(this.contextId);
    			}
    			else {
    				// 获取servlet上下文对象
    				ServletContext sc = getServletContext();
    				// 如果Servlet版本小于2.5,如果web.xml中配置servlet名称则使用其作为上下文的ID
    				if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
    					// 获取servlet上下文名称
    					String servletContextName = sc.getServletContextName();
    					// 如果servetContextName不为null则使用其构建一个Id并设置为WebApplicationContext的ID
    					if (servletContextName != null) {
    						wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName +
    								"." + getServletName());
    					}
    					else {
    						wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getServletName());
    					}
    				}
    				else {
    					// servlet2.5
    					wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
    							ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName());
    				}
    			}
    		}
    		//设置servletContext
    		wac.setServletContext(getServletContext());
    		// 设置servletConfig
    		wac.setServletConfig(getServletConfig());
    		// 设置nameSpace
    		wac.setNamespace(getNamespace());
    		//设置监听器
    		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
    	    //后置处理
    		postProcessWebApplicationContext(wac);
    
    		applyInitializers(wac);
    
    		wac.refresh();
    	}
    
    	
    	protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
    		return createWebApplicationContext((ApplicationContext) parent);
    	}
    
    	/**
    	 * 在WebApplicationContext被刷新前,委派给在当前servlet初始化参数init-param中指定的contextInitializerClasses 类处理
    	 */
    	@SuppressWarnings("unchecked")
    	protected void applyInitializers(ConfigurableApplicationContext wac) {
    		if (this.contextInitializerClasses != null) {
    			String[] initializerClassNames =
    					StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS);
    			for (String initializerClassName : initializerClassNames) {
    				ApplicationContextInitializer<ConfigurableApplicationContext> initializer;
    				try {
    					Class<?> initializerClass = ClassUtils.forName(initializerClassName, wac.getClassLoader());
    					initializer = BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class);
    				}
    				catch (Exception ex) {
    					throw new IllegalArgumentException(
    							String.format("Could not instantiate class [%s] specified via " +
    							"'contextInitializerClasses' init-param", initializerClassName), ex);
    				}
    				this.contextInitializers.add(initializer);
    			}
    		}
    		Collections.sort(this.contextInitializers, new AnnotationAwareOrderComparator());
    		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
    			initializer.initialize(wac);
    		}
    	}
    
    	
    	protected void postProcessWebApplicationContext(ConfigurableWebApplicationContext wac) {
    	}
    
    	
    	public String getServletContextAttributeName() {
    		return SERVLET_CONTEXT_PREFIX + getServletName();
    	}
    
    	public final WebApplicationContext getWebApplicationContext() {
    		return this.webApplicationContext;
    	}
    
    
    	
    	protected void initFrameworkServlet() throws ServletException {
    	}
    
    	/**
    	 * 刷新web应用上下文对象
    	 */
    	public void refresh() {
    		WebApplicationContext wac = getWebApplicationContext();
    		if (!(wac instanceof ConfigurableApplicationContext)) {
    			throw new IllegalStateException("WebApplicationContext does not support refresh: " + wac);
    		}
    		((ConfigurableApplicationContext) wac).refresh();
    	}
    
    	/**
    	 *应用上下文刷新事件监听器回调方法
    	 */
    	public void onApplicationEvent(ContextRefreshedEvent event) {
    		this.refreshEventReceived = true;
    		onRefresh(event.getApplicationContext());
    	}
    
    	/**
    	 *模板方法模式,具体的处理逻辑延迟到子类中
    	 */
    	protected void onRefresh(ApplicationContext context) {
    		// For subclasses: do nothing by default.
    	}
    
    
    	
    
    
    	
    	/**
    	 * Http请求的具体处理方法
    	 **/
    	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		
    		//获取当前时间
    		long startTime = System.currentTimeMillis();
    		Throwable failureCause = null;
    
    		// 获取目前线程持有的LocalContext.
    		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    		//将localContext和当前线程关联
    		LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);
    
    		//获取当前线程持有的RequestAttributes
    		RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
    		
    		ServletRequestAttributes requestAttributes = null;
    		// 如果当前线程没有持有RequestAttributes对象或者持有对象的是ServletReqeustAttributes则创建一个新的ServletREquestAttributes
    		if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) {
    			requestAttributes = new ServletRequestAttributes(request);
    			//与当前线程关联
    			RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
    		}
    
    		if (logger.isTraceEnabled()) {
    			logger.trace("Bound request context to thread: " + request);
    		}
    
    		try {
    		    // 将请求委托给子类的doService方法处理
    			doService(request, response);
    		}
    		catch (ServletException ex) {
    			failureCause = ex;
    			throw ex;
    		}
    		catch (IOException ex) {
    			failureCause = ex;
    			throw ex;
    		}
    		catch (Throwable ex) {
    			failureCause = ex;
    			throw new NestedServletException("Request processing failed", ex);
    		}
    
    		finally {
    			// 清除请求同时复位线程上下文
    			LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);
    			//复位RequestAttributes
    			if (requestAttributes != null) {
    				RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
    				requestAttributes.requestCompleted();
    			}
    			if (logger.isTraceEnabled()) {
    				logger.trace("Cleared thread-bound request context: " + request);
    			}
    
    			if (logger.isDebugEnabled()) {
    				if (failureCause != null) {
    					this.logger.debug("Could not complete request", failureCause);
    				}
    				else {
    					this.logger.debug("Successfully completed request");
    				}
    			}
    			// 如果需要发布一个请求处理完成的事件则发送该事件
    			if (this.publishEvents) {
    				// Whether or not we succeeded, publish an event.
    				long processingTime = System.currentTimeMillis() - startTime;
    				//发布一个ServeltReqeustHandledEvent事件,用户可以对该事件进行监听
    				this.webApplicationContext.publishEvent(
    						new ServletRequestHandledEvent(this,
    								request.getRequestURI(), request.getRemoteAddr(),
    								request.getMethod(), getServletConfig().getServletName(),
    								WebUtils.getSessionId(request), getUsernameForRequest(request),
    								processingTime, failureCause));
    			}
    		}
    	}
    
    	
    	protected LocaleContext buildLocaleContext(HttpServletRequest request) {
    		return new SimpleLocaleContext(request.getLocale());
    	}
    
    	
    	protected String getUsernameForRequest(HttpServletRequest request) {
    		Principal userPrincipal = request.getUserPrincipal();
    		return (userPrincipal != null ? userPrincipal.getName() : null);
    	}
    
    	/**
    	 *  模板方法模式,将具体实现延迟到子类中
    	 **/
    	protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
    			throws Exception;
    
    
    	/**
    	 * 关闭应用上下文
    	 */
    	@Override
    	public void destroy() {
    		getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");
    		if (this.webApplicationContext instanceof ConfigurableApplicationContext) {
    			((ConfigurableApplicationContext) this.webApplicationContext).close();
    		}
    	}
    
    
    	/**
    	 * 应用上下文监听器
    	 */
    	private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
    
    		public void onApplicationEvent(ContextRefreshedEvent event) {
    			 //
    			FrameworkServlet.this.onApplicationEvent(event);
    		}
    	}
    
    }
    

     后续请见 DispatcherServlet初始化处理

  • 相关阅读:
    Android Architecture Components
    adb命令
    Dagger2 scope
    Dagger2学习资源
    Dependency Injection学习笔记
    什么是ADB
    使用AndroidStudio dump heap,再用 Eclipse MAT插件分析内存泄露
    Dagger学习笔记
    linux & shell & nginx & Docker Kubernetes
    Go 目录
  • 原文地址:https://www.cnblogs.com/wei-zw/p/8797761.html
Copyright © 2011-2022 走看看