SpringMVC配置及源码分析

一、环境搭建

  1. 创建一个web项目。
  • 如果是maven项目,则直接在pom中加入springMvc依赖
    
        
            javax.servlet
            javax.servlet-api
            3.1.0
        
        
            org.springframework
            spring-webmvc
            4.1.9.RELEASE
        
    

如果不是就从把这些jar包丢到lib里面

SpringMVC配置及源码分析_第1张图片

二、SpringMVC配置

  1. 在web中配置servlet,
    url-pattern中的/ 和 / * 有区别
    / 不会匹配到*.jsp,即:*.jsp不会进入spring的 DispatcherServlet类 。
    /* 会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。


    
    
        springMvc
        org.springframework.web.servlet.DispatcherServlet
    
    
        springMvc
        /
    
    

  • 创建springMvc-servlet.xml文件,放到WEB-INF路径下


    
    
     
    
        
        
    

三、测试

创建Controller:

@Controller
public class HelloWorld {
    @ResponseBody
    @RequestMapping("/helloworld")
    public String helloWorld(){
        return "Hello world";
    }
    @RequestMapping("/hello")
    public String hello(Model model){
        model.addAttribute("msg","hello");
        return "/hello";
    }
}

创建资源文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


    ${msg}


然后把项目丢到tomcat中启动,访问/helloworld就能够看见Hello world了,访问/hello能够看到hello

四、源码分析

SpringMVC配置及源码分析_第2张图片
springMvc 核心 servlet 结构图

SpringMVC的servlet的有三个层次:分别是HttpServletBean、FrameworkServlet、DispatcherServlet。

初始化

  1. HttpServletBean初始化
    HttpServletBean直接继承了java的HttpServlet,创建时自动调用init方法进行初始化
    @Override
    public final void init() throws ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("Initializing servlet '" + getServletName() + "'");
        }
        // Set bean properties from init parameters.
        try {
            PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
            // 使用BeanWrapper构造DispatcherServlet
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true); // 设置DispatcherServlet属性
        }
        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");
        }
    }
  1. FrameworkServlet初始化
    FrameworkServlet是HttpServletBean类的子类,所以初始化操作是覆盖initServletBean
    @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 {
            // initServletBean的主要方法,初始化webApplicationContext
            this.webApplicationContext = initWebApplicationContext();
            // 这个里面没有任何实现方法
            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");
        }
    }
    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext()); // 得到根上下文
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            wac = createWebApplicationContext(rootContext); // 创建一个WebApplicationContext
        }

        if (!this.refreshEventReceived) {
            onRefresh(wac); // 模板方法,子类DispatcherServlet会覆盖这个方法进行初始化
        }

        if (this.publishContext) {
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac); // 将新创建的容器设置到ServletContext中去
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
                        "' as ServletContext attribute with name [" + attrName + "]");
            }
        }

        return wac;
    }
  1. DispatcherServlet初始化
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }
    protected void initStrategies(ApplicationContext context) {
        //初始化多媒体解析器  
        initMultipartResolver(context);  
        //初始化位置解析器  
        initLocaleResolver(context);  
        //初始化主题解析器  
        initThemeResolver(context);  
        //初始化HandlerMappings  
        initHandlerMappings(context);  
        // 初始化HandlerAdapters  
        initHandlerAdapters(context);  
        //初始化异常解析器  
        initHandlerExceptionResolvers(context);  
        //初始化请求到视图名转换器  
        initRequestToViewNameTranslator(context);  
        //初始化视图解析器  
        initViewResolvers(context);  
        //初始化FlashMapManager  
        initFlashMapManager(context);  
    }

请求处理

  1. HttpServletBean请求处理
    HttpServletBean没有进行任何请求处理,只是参与了容器的初始化操作
  2. FrameworkServlet请求处理
    service方法是HttpServlet中的方法,servlet容器把所有请求发送到该方法,该方法默认行为是转发http请求到doXXX方法中,如果重载了该方法,默认操作被覆盖,不再进行转发操作
    FrameworkServlet重写了service方法,如果Http请求为PATCH则使用processRequest处理,否则使用父类的service去处理
    但是除了doOptions、doTrace这两个方法FrameworkServlet用了自己的实现,其他的处理最后都使用的是processRequest
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        if (RequestMethod.PATCH.name().equalsIgnoreCase(request.getMethod())) {
            processRequest(request, response);
        }
        else {
            super.service(request, response);
        }
    }

processRequest是FrameworkServlet这个类中最核心的方法

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;

        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        LocaleContext localeContext = buildLocaleContext(request);

        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

        initContextHolders(request, localeContext, requestAttributes);
        // 上面一大堆都是用于初始化一些乱七八糟的东东,下面的才是处理请求的
        try {
            // 模板方法,交由子类DispatcherServlet去处理
            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 {
            resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }

            if (logger.isDebugEnabled()) {
                if (failureCause != null) {
                    this.logger.debug("Could not complete request", failureCause);
                }
                else {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        logger.debug("Leaving response open for concurrent processing");
                    }
                    else {
                        this.logger.debug("Successfully completed request");
                    }
                }
            }

            publishRequestHandledEvent(request, response, startTime, failureCause);
        }
    }
  1. DispatcherServlet请求处理

DispatcherServlet对于请求分为两步,第一步是请求处理,第二步是渲染页面
如果请求进来,会调用DispatcherServlet的doService方法去进行处理

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (logger.isDebugEnabled()) {
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
            logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                    " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
        }

        Map attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
        // 上面对请求进行了一些处理,doDispatch才是去处理请求的方法
        try {
            doDispatch(request, response);
        }
        finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                if (attributesSnapshot != null) {
                    restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                // 检查是不是上传请求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // 去找对应的请求处理器
                mappedHandler = getHandler(processedRequest);
                // 如果找不到对应的请求处理器则直接返回404错误
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
                // 根据请求处理器,获取执行操作的请求适配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // 获取请求的方式
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                // head请求和get一樣,只是head只会取的HTTP header的信息。
                if (isGet || "HEAD".equals(method)) {
                    // lastModified 属性可返回文档最后被修改的日期和时间。
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    // checkNotModified逻辑判断当前lastModfied值和http header的上次缓存值,如果还没有过期就设置304头并且返回并结束整个请求流程。否则继续。
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // 实际上执行处理的方法,通过请求访问对应的处理器,并且返回modelandview对象
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                // 如果是异步请求直接返回
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                // 设置默认的视图
                applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            // 处理返回结果。包括异常处理、渲染页面、发成完成通知出发Interceptor的afterCompletion
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            // 判断是否异步
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // 删除上传请求的资源
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

你可能感兴趣的:(SpringMVC配置及源码分析)