SpringMVC详解

一.搭建项目

1.新建项目 选中Spring ->Spring MVC 模块 点击next 和 Finish


注意:将生产的lib文件移动到WEB-INF目录下

2.配置 web.xml和SpringMVCxml文件


        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

        version="4.0">

   

        contextConfigLocation

        /WEB-INF/applicationContext.xml

   

   

        org.springframework.web.context.ContextLoaderListener

   

   

        dispatcher

        org.springframework.web.servlet.DispatcherServlet

       

            contextConfigLocation

            /WEB-INF/springmvc.xml

       

        1

   

   

        dispatcher

        /

   


      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns:context="http://www.springframework.org/schema/context"

      xmlns:mvc="http://www.springframework.org/schema/mvc"

      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd

        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

   

   

   

   

       

       

   


3.添加index.jsp文件 在WEB-INF/views目录下


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

 

    $Title$

 

 

  ${message}

 


4.添加handler处理器


@Controller

class HelloController {

    @RequestMapping("/hello")

    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {

        ModelAndView mav = new ModelAndView("index");

        mav.addObject("message", "Hello Spring MVC");

        return mav;

    }

    @RequestMapping("/helloRes")

    @ResponseBody

    public String helloResponse() {

        return "hello SpringMVC";

    }

}

5.添加本地tomcat启动项目

1.edit configration中选中local tomcat


2.选中项目war包


注意 application context 可以理解是项目的对外名称,端口后必须和配置的一致

6.启动tomcat



二执行流程

1.时序图


2.执行流程

1、前端请求到前端控制器DispatcherServlet

2、DispatcherServlet收到请求调用处理映射器HandlerMapping

3、处理映射器根据请求url找到具体的处理器(ApplicationContext初始化时用Map保存所有的url和controller对应关系),生成处理器执行链HandlerExecutionChain(包含处理器对象和处理器拦截器)返回给DispatcherServlet

4、DispatcherServlet根据处理器Handler获取对应的适配器

5、HandlerAdapter调用处理器Handler找到具体的Controller

6、Controller 执行完成后返回ModelAndView

7、HandlerAdapter返回ModelAndView

8、DispatcherServlet统一将返回的ModelAndView派送到ViewResolve(视图解析器)解析

9,视图解析器解析之后返回 View

10、对View进行渲染

11、回显页面

3.容器的初始化

1.DispatcherServlet的父类HttpServletBean中找到初始化的init()方法;

2.在init()方法中又会调用FrameworkServlet类的initServletBean()方法,最终会调用refresh()方法;

3.IOC容器初始化完成之后会调用DispatcherServlet类的onRefresh()方法,完成SpringMVC九大组件的初始化。

三.源码分析(5.2.3)

一.将请求和url与Controller绑定

1.在spring容器启动时,在实例化Controller bean后,调用afterPropertiesSet() ->initHandlerMethods()->

processCandidateBean() ->detectHandlerMethods 解析bean的方法

```java

protected void detectHandlerMethods(Object handler) {

        Class handlerType = handler instanceof String ? this.obtainApplicationContext().getType((String)handler) : handler.getClass();

        if (handlerType != null) {

            Class userType = ClassUtils.getUserClass(handlerType);

            Map methods = MethodIntrospector.selectMethods(userType, (method) -> {

                try {

                    return this.getMappingForMethod(method, userType);

                } catch (Throwable var4) {

                    throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, var4);

                }

            });

            if (this.logger.isTraceEnabled()) {

                this.logger.trace(this.formatMappings(userType, methods));

            }

            methods.forEach((method, mapping) -> {

                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);

                // 为每个方法绑定url

                this.registerHandlerMethod(handler, invocableMethod, mapping);

            });

        }

    }

```

给每个controller中的方法绑定url

```java

public void register(T mapping, Object handler, Method method) {

            if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && AbstractHandlerMethodMapping.KotlinDelegate.isSuspend(method)) {

                throw new IllegalStateException("Unsupported suspending handler method detected: " + method);

            } else {

                this.readWriteLock.writeLock().lock();

                try {

                    HandlerMethod handlerMethod = AbstractHandlerMethodMapping.this.createHandlerMethod(handler, method);

                    this.validateMethodMapping(handlerMethod, mapping);

                    // 映射关系放入map中

                    this.mappingLookup.put(mapping, handlerMethod);

                    List directUrls = this.getDirectUrls(mapping);

                    Iterator var6 = directUrls.iterator();

                    while(var6.hasNext()) {

                        String url = (String)var6.next();

                        this.urlLookup.add(url, mapping);

                    }

                    String name = null;

                    if (AbstractHandlerMethodMapping.this.getNamingStrategy() != null) {

                        name = AbstractHandlerMethodMapping.this.getNamingStrategy().getName(handlerMethod, mapping);

                        this.addMappingName(name, handlerMethod);

                    }

                    CorsConfiguration corsConfig = AbstractHandlerMethodMapping.this.initCorsConfiguration(handler, method, mapping);

                    if (corsConfig != null) {

                        this.corsLookup.put(handlerMethod, corsConfig);

                    }

                    this.registry.put(mapping, new AbstractHandlerMethodMapping.MappingRegistration(mapping, handlerMethod, directUrls, name));

                } finally {

                    this.readWriteLock.writeLock().unlock();

                }

            }

```

二.前端请求找到对应的Controller

根据servlet的 service()方法->doService()->doDispatch()

```java

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

        HttpServletRequest processedRequest = request;

        HandlerExecutionChain mappedHandler = null;

        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {

            try {

                ModelAndView mv = null;

                Object dispatchException = null;

                try {

                    processedRequest = this.checkMultipart(request);

                    multipartRequestParsed = processedRequest != request;

                    // 获取handle

                    mappedHandler = this.getHandler(processedRequest);

                    if (mappedHandler == null) {

                        this.noHandlerFound(processedRequest, response);

                        return;

                    }

// 获取adapter

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());

                    String method = request.getMethod();

                    boolean isGet = "GET".equals(method);

                    if (isGet || "HEAD".equals(method)) {

                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {

                            return;

                        }

                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {

                        return;

                    }

// 调用handler的具体方法

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                    if (asyncManager.isConcurrentHandlingStarted()) {

                        return;

                    }

                    this.applyDefaultViewName(processedRequest, mv);

                    mappedHandler.applyPostHandle(processedRequest, response, mv);

                } catch (Exception var20) {

                    dispatchException = var20;

                } catch (Throwable var21) {

                    dispatchException = new NestedServletException("Handler dispatch failed", var21);

                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);

            } catch (Exception var22) {

                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);

            } catch (Throwable var23) {

                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));

            }

        } finally {

            if (asyncManager.isConcurrentHandlingStarted()) {

                if (mappedHandler != null) {

                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

                }

            } else if (multipartRequestParsed) {

                this.cleanupMultipart(processedRequest);

            }

        }

    }

```

handleInternal

```java

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        this.checkRequest(request);

        ModelAndView mav;

        if (this.synchronizeOnSession) {

            HttpSession session = request.getSession(false);

            if (session != null) {

                Object mutex = WebUtils.getSessionMutex(session);

                synchronized(mutex) {

                    mav = this.invokeHandlerMethod(request, response, handlerMethod);

                }

            } else {

                mav = this.invokeHandlerMethod(request, response, handlerMethod);

            }

        } else {

            mav = this.invokeHandlerMethod(request, response, handlerMethod);

        }

        if (!response.containsHeader("Cache-Control")) {

            if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

                this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);

            } else {

                this.prepareResponse(response);

            }

        }

        return mav;

    }

```

invokeHandlerMethod

```java

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        ModelAndView var15;

        try {

            WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);

            ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);

            ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);

            if (this.argumentResolvers != null) {

                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);

            }

            if (this.returnValueHandlers != null) {

                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

            }

            invocableMethod.setDataBinderFactory(binderFactory);

            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

            ModelAndViewContainer mavContainer = new ModelAndViewContainer();

            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

            modelFactory.initModel(webRequest, mavContainer, invocableMethod);

            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);

            asyncWebRequest.setTimeout(this.asyncRequestTimeout);

            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

            asyncManager.setTaskExecutor(this.taskExecutor);

            asyncManager.setAsyncWebRequest(asyncWebRequest);

            asyncManager.registerCallableInterceptors(this.callableInterceptors);

            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

            Object result;

            if (asyncManager.hasConcurrentResult()) {

                result = asyncManager.getConcurrentResult();

                mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];

                asyncManager.clearConcurrentResult();

                LogFormatUtils.traceDebug(this.logger, (traceOn) -> {

                    String formatted = LogFormatUtils.formatValue(result, !traceOn);

                    return "Resume with async result [" + formatted + "]";

                });

                invocableMethod = invocableMethod.wrapConcurrentResult(result);

            }

            invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);

            if (asyncManager.isConcurrentHandlingStarted()) {

                result = null;

                return (ModelAndView)result;

            }

            var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);

        } finally {

            webRequest.requestCompleted();

        }

        return var15;

    }

```

invokeAndHandle 反射调用方法

```java

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

// 反射调用Controller中的具体方法

        Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);

        this.setResponseStatus(webRequest);

        if (returnValue == null) {

            if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {

                this.disableContentCachingIfNecessary(webRequest);

                mavContainer.setRequestHandled(true);

                return;

            }

        } else if (StringUtils.hasText(this.getResponseStatusReason())) {

            mavContainer.setRequestHandled(true);

            return;

        }

        mavContainer.setRequestHandled(false);

        Assert.state(this.returnValueHandlers != null, "No return value handlers");

        try {

            this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);

        } catch (Exception var6) {

            if (this.logger.isTraceEnabled()) {

                this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);

            }

            throw var6;

        }

    }

```

解析结果,渲染视图

```java

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {

        boolean errorView = false;

        if (exception != null) {

            if (exception instanceof ModelAndViewDefiningException) {

                this.logger.debug("ModelAndViewDefiningException encountered", exception);

                mv = ((ModelAndViewDefiningException)exception).getModelAndView();

            } else {

                Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;

                mv = this.processHandlerException(request, response, handler, exception);

                errorView = mv != null;

            }

        }

        if (mv != null && !mv.wasCleared()) {

        // 渲染视图

            this.render(mv, request, response);

            if (errorView) {

                WebUtils.clearErrorRequestAttributes(request);

            }

        } else if (this.logger.isTraceEnabled()) {

            this.logger.trace("No view rendering, null ModelAndView returned.");

        }

        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

            if (mappedHandler != null) {

                mappedHandler.triggerAfterCompletion(request, response, (Exception)null);

            }

        }

    }

```

你可能感兴趣的:(SpringMVC详解)