spring-mvc-boot-1 框架设计流程

一、MVC架构

二、springMVC全流程


                                 

三、流程简单描述

@Controller      控制器【控制器指根据req处理返回res的程序】
@RequestMapping  映射器【请求路径:控制器】 【HandlerMapper机制】 返回【HandlerExecutionChain=handler+handlerInterceptors】处理器责任链
handler          处理器【控制器后的实际处理,是对控制器的包装】
interceptors     拦截器【增强处理器功能】
handlerAdapter   适配器【得到处理器后不能直接运行,运行需要适配器】【运行HandlerExecutionChain】
                       【执行控制器返回JSON,轮询匹配Converter】【匹配则设置视图null】
ModelAndView     数据模型【模型Model+视图View】【data/user】                       
ViewResolver     视图解析器

四、阐述

springMVC和boot可以说是烂大街的普及度了。自己也用了好写年,阐述一下自己的看法,希望可以帮助大家更好的理解。

1、这里面springMVC的流程和组件是核心。很重要的就是DispatcherServlet,可是说是个开头。

2、因为springMVC和boot都是配置模式,往往是不清不楚就是开始,甚至不清不楚就完成了,所以很多写代码的老江湖其实未必知道详细的流程细节,会用却不那么懂,是很多程序员的通病。甚至一些老程序员直言,上手快就行。

我只能说,当一个老外包这样是可以的,但哄着自己玩有什么意思。热爱代码的人是不会这么看待这个问题的。

说到这里,不禁有一个灵魂问题,热爱代码有什么用?

好吧,负责任的说,并无卵用。就和你玩俄罗斯方块多过几关一样。

扯淡了,继续。

3、在springBoot机制启动后,DispactherSrvlet、HandlerAdapter等对象组件就会被初始化。其实你都不用管这些,总之记住这个springMVC相关的Bean就会存放好在spring的Bean工厂中,供应用调用。

这些组件,基本上就是:处理器、适配器、控制器、数据模型、解析器等等。

4、数据模型其实是大家最熟悉的,因为这玩意只能自己写,用到的多,所以了解。其他组件其实也和这个差不多,不难,但是用的少,我是说人家组件就在那里,你直接用是用,这不和没正经用一样吗?

5、所谓的学习springMVC,其实就是对这些组件的掌握程度了。当然,大神另算,大略就是指像我这样多少年后又无聊摸起代码的N流程序员吧。

6、映射选择器,处理器

springMVC的处理器到底是个啥?说实话,其实是两个东西,一个是映射选择器。

这个东西其实用大白话说,就是我们客户端请求的url,服务端收到这个请求以后,给穿了一件马甲,url+马甲=映射选择器。

换成类就是HandlerMapping。

这个东西很重要,就拿三国来说,前三国吕布,后三国赵云。这玩意就是个吕布。整个springMVC的前半程都是为绕它展开的。

url包装成为了HandlerMapping。

package org.springframework.web.servlet;
public interface HandlerMapping {
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

7、HandlerMapping是什么?HandlerExecutionChain是什么?

那么,新的问题来了,HandlerMapping要做什么?

HandlerMapping会通过url,把这url请求映射成为HandlerExecutionChain。

这又是什么东东?其实这是设计模式中的责任链模式,说的直白一点,就是两个东西:

(1)handler

  (2)   chain链 里面全是拦截器HandlerInterceptor

通过这种方式,让HandlerMapping成为或者串联一一大堆可以控制的组件。

特别注意,模板责任链这种设计模式,是HandlerMapping的关键思路。

针对springMVC请求处理这一块,你只需要记住:url穿马甲,马甲绑了责任链。

(3)封装

只负责找,却不负责执行,执行交给处理器或适配器做。

HandlerMapping是处理器映射器,根据请求找到处理器Handler,但并不是简单的返回处理器,而是将处理器和拦截器封装,形成一个处理器执行链(HandlerExecuteChain)。

HandlerMapping执行流程如下:

DispatcherServlet
--->doDispatcher()
---->getHandler(request):
---->HandlerExecutionChain
------> hm.getHandler(request)-----》方法体中
----->ExecutionChain executionChain = getHandlerExecutionChain(handler, request);
----->new HandlerExecutionChain(handler)
----->chain.addInterceptor(interceptor);

8、适配器

HandlerAdapter适配器,今天没时间了,改天聊。

---------------------------------

接着写适配器,了解这个之前,要知道设计模式中的适配器模式。这是个什么东西呢?

码代码的人应该有人买过美版电脑吧,插座上都有一个适配器。

对,你理解的不错,就那个东西。

适配器模式也和这个适配器大差不差。

简单的说,就是你直接插,插不上,我给你做个转换器用用。

这个HandlerAdapter就是后三国的赵云。

到了这里,就需要明白HandlerAdapter到底干了什么?

9、适配器到底干了什么?

HandlerAdapter解决了一个问题,即如何处理请求的策略。

public interface HandlerAdapter {  
    //判断是否支持传入的Handler
    boolean supports(Object handler);  
    //用来使用Handler处理请求
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;  
    //用来获取资料的Last-Modified值
    long getLastModified(HttpServletRequest request, Object handler);  
}

具体来说:

(1)通过请求url、请求Method和requestMapping定义,最终确定使用处理类的哪个方法来处理请求。

(2)确定如何转换需要的参数传入调用方法

(3)最终调用返回ModelAndView。

(4) 通过调用handlerAdapter中的handler方法

总结下:

一、handlerAdapter这个类的作用就是接过handlermapping解析请求得到的handler对象。在更精确的定位到能够执行请求的方法。

具体来说:

二、根据handlerMapping传过来的Handler对象,DispatcherServlet将自己的HandlerAdapter集合与之一一匹配。如果有支持Handler对象的HandlerAdapter,那么HandlerAdapter就会调用自己的 handle方法处理请求。

10、适配器的工作流程工作流程

(1)DispatcherServlte会根据handlerMapping传过来的controller与已经注册好了的HandlerAdapter 一一匹配,看哪一种HandlerAdapter是支持该controller类型的。

(2)如果找到了其中一种HandlerAdapter是支持传过来的 controller类型,那么该HandlerAdapter会调用自己的handle方法。

(3)HandlerAdapter的handle只是做了一些模板化的工作。最终依然是通过反射调用了controller的自我实现代码。

(4)这里有一个类值得研究:RequestMappingHandlerAdapter。因为它真正意义上实现了HandlerAdapter 接口定义的功能。

handleInternal() 负责调用 HandlerMethod(处理器),并返回 ModelAndView。

protected boolean supportsInternal(HandlerMethod handlerMethod) {
    return true;
}

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, 
    HandlerMethod handlerMethod) throws Exception {
    // 1.校验请求
    // 检查是否支持当前 rqeuest 的 method 和 session
    checkRequest(request);

    // 2.判断控制器是否存在 @SessionAttributes 注解
    if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
        // 2.1设置缓存
        applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
    } else {
        // 2.2准备响应
        prepareResponse(response);
    }

    // 默认为 false,为 true 表示在同步块中执行 invokeHandlerMethod
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                return invokeHandlerMethod(request, response, handlerMethod);
            }
        }
    }
    // 关键 -> 3.处理器调用
    return invokeHandlerMethod(request, response, handlerMethod);
}
private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,HandlerMethod handlerMethod) throws Exception {
	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
	ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
	ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

	ModelAndViewContainer mavContainer = new ModelAndViewContainer();
	mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
	modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
	mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

        //执行Controller中的RequestMapping注释的方法  
	requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
	modelFactory.updateModel(webRequest, mavContainer);

	if (mavContainer.isRequestHandled()) {
		return null;
	}
	else {
		ModelMap model = mavContainer.getModel();
                //返回ModelAndView视图  
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		if (model instanceof RedirectAttributes) {
			Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
		}
		return mav;
	}
}

11、视图解析器

======大头基本结束,有空在写视图,目前大部分前后端分离,其实给json就挺好的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良之才-小良

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值