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 = ",; \t\n";

    /**
     *
     */
    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初始化处理

DispatchServlet源码分析

  • qq_43638135
    妲己再美究为妃: 博主没有想过自己接一些私活干吗?我现在还没毕业,但是我也确实听说外挂市场自动化游戏脚本市场挺火热的,并且报酬也很丰厚,但是具体的我也不是很清楚,求解答。 (1个月前 #47楼) 查看回复(2) 举报 回复
    22