Spring MVC 核心组件

MVC 核心组件

MVC 是软件工程中一种架构模式,将软件系统分成三个基本部分,模型,视图,控制器,由施乐研究中心为 SmallTalk 发明的一种软件设计模式

DispatcherServlet

* 在实际使用中,Spring 会通过扫描组件的方式,将组件装配到 WebApplicationContext 中,
  在请求到达 Servlet 后,最终会由 DispatcherServlet.doDispatch 处理

* 本质上 DispatcherServlet 会将请求委派给一些特殊的 Bean 来进行请求的处理和响应的渲染

* 当请求在 Servlet WebApplicationContext 中无法处理,便会委派给 Root WebApplicationContext
  这一现象是 Spring REST Repository 的实现原理

* DispatcherServlet 可以对 Http 消息的头部进行修改吗?
    不可以,Http 消息的头部应使用 Servlet API 进行设置
构造方法
// 使用 WebApplicationContext 加载特定的 Bean
public DispatcherServlet(WebApplicationContext webApplicationContext) {
        super(webApplicationContext);
        this.setDispatchOptionsRequest(true);
    }
render 方法
// render 方法用于进行国际化处理和视图的渲染
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
        // 进行国际化处理
        response.setLocale(locale);
        String viewName = mv.getViewName();
        View view;
        if (viewName != null) {
            view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
            if (view == null) {
                String var10002 = mv.getViewName();
                throw new ServletException("Could not resolve view with name '" + var10002 + "' in servlet with name '" + this.getServletName() + "'");
            }
        } else {
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
            }
        }

        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Rendering view [" + view + "] ");
        }

        try {
            if (mv.getStatus() != null) {
                request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
                response.setStatus(mv.getStatus().value());
            }

            view.render(mv.getModelInternal(), request, response);
        } catch (Exception var8) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Error rendering view [" + view + "]", var8);
            }

            throw var8;
        }
    }
getHandler 方法
    // getHandler 用于返回请求对应的处理器也就是 HandlerExecutionChain
    // HandlerExecutionChain 包含拦截器 preHandle handle postHandle 的具体处理逻辑
    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }
doDispatch 方法
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;
                Exception dispatchException = null;

                try {
                    // 处理 multipart 请求(如果有),例如文件上传
                    processedRequest = this.checkMultipart(request);
                    // 检查请求是否已被 multipart 解析
                    multipartRequestParsed = processedRequest != request;
                    // 调用 getHandler 方法并根据请求查找对应的处理器
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        // 如果没有返回 404
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    // 对 GET 请求和 HEAD 请求做特殊优化
                    boolean isGet = HttpMethod.GET.matches(method);
                    if (isGet || HttpMethod.HEAD.matches(method)) {
                        // 检查资源文件是否已被修改
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;  // 资源未修改,直接返回 304 让浏览器使用缓存
                        }
                    }
                    // 对请求进行预处理
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    //  对请求进行处理,返回 ModelAndView 对象
                    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 ServletException("Handler dispatch failed: " + var21, var21);
                }
                // 调用 processDispatchResult 进行视图渲染
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                triggerAfterCompletion(processedRequest, response, mappedHandler, new ServletException("Handler processing failed: " + var23, var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }
// HEAD 方法只返回响应状态行和响应头,通常用于 ETAG 或 Accept-Ranges
processDispatchResult 方法
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) {
                ModelAndViewDefiningException mavDefiningException = (ModelAndViewDefiningException)exception;
                this.logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = mavDefiningException.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);
            }

        }
    }

ViewResolver

 

* ViewResolver 负责将 controller 的返回值交给对应的 View 处理,每一种模板引擎都需要有自己的 ViewResolver 实现

* 模板引擎的 ViewResolver 一般会继承 UrlBasedViewResolver,UrlBasedViewResolver 中定义了两种特殊的常量:
    - REDIRECT_URL_PREFIX = "redirect:" 用于重定向
    - FORWARD_URL_PREFIX = "forward:" 用于转发

HandlerMapping

* 应用程序中所有的 HandlerMapping 都存放在 DispatcherServlet 的 HandlerMappings 中
* HandlerExecutionChain 

* Spring 的默认 HandlerMapping 实现是 RequestMappingHandlerMapping,该 HandlerMapping 
  用于处理 RequestMapping、GetMapping 

ModelAndView

* 包含视图名和数据的对象,由 HandlerAdapter 返回,另外无论 Controller 返回了 String、
  Model String、ModelAndView 最总都会被 ModelAndViewMethodReturnValueHandler 处理
  成 ModelAndView
MVVC 模型-视图-视图模型是 MVC 软件架构的衍生,该架构的核心特点是模型和视图的双向绑定

写在最后 

Spring MVC 的核心组件
    * DispatcherServlet:前端控制器,拦截请求并分发给合适的控制器。
    * Controller:接收请求并返回模型给视图解析器
    * ViewResolver:视图解析器,解析模型并返回具体的视图对象给客户端。
    * ModelAndView:包含模型和视图的复合对象。
    * WebMvcConfigurer 拦截器,消息转换器,过滤器,跨域的核心注册中心
  • 17
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值