当前位置: 首页 > news >正文

21-mvc 体系结构源码详解

专栏目录

  1. 1-Spring架构源码分析-Spring源码搭建
  2. 2-Spring架构源码分析-SSM框架说明
  3. 3-Spring架构源码分析-spring体系
  4. 4-Spring架构源码分析-Spring IOC机制设计思想和源码解读
  5. 5-Spring架构源码分析-Spring IOC之 Spring 统一资源加载策略
  6. 6-Spring架构源码分析-IoC 之加载 BeanDefinition
  7. 7-Spring架构源码分析-IoC 之注册 BeanDefinitions
  8. 8-Spring架构源码分析-IoC 之解析Bean:解析 import 标签
  9. 9-Spring架构源码分析-IoC 之解析 bean 标签:开启解析进程
  10. 10-Spring架构源码分析-IoC 之解析 bean标签:BeanDefinition
  11. 11-Spring架构源码分析-IoC 之注册解析的 BeanDefinitions
  12. 12-Spring架构源码分析-IoC 之装载 BeanDefinitions 总结
  13. 13-Spring架构源码分析-IoC 之开启 Bean 的加载
  14. 14-Spring架构源码分析-IoC 之加载 Bean:总结
  15. 15-Spring架构源码分析-Spring代理与AOP
  16. 16-Spring AOP源码分析-@EnableAspectJAutoProxy和AspectJAutoProxyRegistrar
  17. 17-Spring AOP源码分析-AnnotationAwareAspectJAutoProxyCreator
  18. 18-Spring AOP源码分析-AOP与BeanPostProcessor处理器
  19. 19-Spring AOP源码分析-代理对象调用目标方法
  20. 20-spring mvc设计思想和源码解读-spring mvc 功能特性
  21. 21-mvc 体系结构源码详解
  22. 22-Spring MVC源码跟踪
  23. 23-Spring事务源码分析

mvc 体系结构详解

spring mvc 框架解决的问题

从技术角度去思考 任何一个现存的框架都有其存在理由,而这个理由就是解决实际的问题。或者提供更好的解决问题的方案。spring mvc 它解决了什么问题呢?

  1. URL映射
  2. 表单参数映射
  3. 调用目标Control
  4. 数据模型映射
  5. 视图解析
  6. 异常处理

上术解决在spring mvc 中都体现在如下组件当中

  • **HandlerMapping **'hændlə 'mæpɪŋ
    • url与控制器的映射
  • HandlerAdapter 'hændlə ə’dæptə
    • 控制器执行适配器
  • **ViewResolver **vjuː riː’zɒlvə
    • 视图仓库
  • view
    • 具体解析视图
  • **HandlerExceptionResolver **'hændlə ɪk’sepʃ(ə)n riː’zɒlvə
    • 异常捕捕捉器
  • HandlerInterceptor 'hændlə ɪntə’septə
    • 拦截器
      在这里插入图片描述

mvc 各组件执行流程
在这里插入图片描述

HandlerMapping 详解

其为mvc 中url路径与Control对像的映射,DispatcherServlet 就是基于此组件来寻找对应的Control,如果找不到就会报 No mapping found for HTTP request with URI的异常。

HandlerMapping 接口结构分析:
在这里插入图片描述

HandlerMapping 作用是通过url找到对应的Handler ,但其HandlerMapping.getHandler()方法并不会直接返回Handler 对象,而是返回 HandlerExecutionChain 对象在通过 HandlerExecutionChain.getHandler() 返回最终的handler

在这里插入图片描述

常用实现类:
在这里插入图片描述

目前主流的三种mapping 如下:

  1. SimpleUrlHandlerMapping:基于手动配置 url 与control 映射
  2. BeanNameUrlHandlerMapping: 基于ioc name 中已 “/” 开头的Bean时行 注册至映射.
  3. RequestMappingHandlerMapping:基于@RequestMapping注解配置对应映射

SimpleUrlHandlerMapping
演示基于 SimpleUrlHandlerMapping配置映射。
编写mvc 文件

	<!--需要放在前面<mvc:default-servlet-handler/>,不然不起作用-->
	<!--SimpleUrlHandlerMapping只支持实现了Controller接口的bean,且还需要在其属性里进行url路径==>bean的映射,不支持@RequestMapping注解-->
	<bean id="urlMappingController" class="com.naixue.web.UrlMappingController"/>
	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/urlMapping">urlMappingController</prop>
			</props>
		</property>
	</bean>

SimpleUrlHandlerMapping体系结构:

image-20201020205047955

初始化SimpleUrlHandlerMapping流程关键源码:

org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#setUrlMap
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#initApplicationContext
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#registerHandlers
// /表示根路径 /* 表示默认路径
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#registerHandler()

获取 Handler流程关键源码:

org.springframework.web.servlet.DispatcherServlet#doService
org.springframework.web.servlet.DispatcherServlet#doDispatch
org.springframework.web.servlet.DispatcherServlet#getHandler
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#getHandlerInternal
// 获取URL路径
org.springframework.web.util.UrlPathHelper#getPathWithinApplication
// 查找handler
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#lookupHandler
// 封装执行链
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain

BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping 实现上与 SimpleUrlHandlerMapping 一至,唯一区别在于 继承自AbstractDetectingUrlHandlerMapping ,通过对应detectHandlers 可以在无配置的情况下发现url 与handler 映射。
结构图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f6mYEdSd-1662071432790)(https://gitee.com/onlycreator/draw/raw/master/img/image-20201020204620343.png)]

RequestMappingHandlerMapping
其基于注解实现,在后续章节讲解注解映射的时候在详细讲。

Handler 类型
在 AbstractUrlHandlerMapping 我们可以看到存储handler 的Map 值类型是Object ,是否意味着所有的类都可以做来Handler 来使用?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c3dTJTZ9-1662071432791)(https://gitee.com/onlycreator/draw/raw/master/img/image-20201021145001157.png)]

protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
		Assert.notNull(urlPath, "URL path must not be null");
		Assert.notNull(handler, "Handler object must not be null");
		Object resolvedHandler = handler;

		// Eagerly resolve handler if referencing singleton via name.
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			ApplicationContext applicationContext = obtainApplicationContext();
			if (applicationContext.isSingleton(handlerName)) {
        //可以看出实际是put了一个bean为handler
				resolvedHandler = applicationContext.getBean(handlerName);
			}
		}

		......
		this.handlerMap.put(urlPath, resolvedHandler);
		...
		}
	}

Handler 对应类型如下如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C686kT9E-1662071432792)(https://gitee.com/onlycreator/draw/raw/master/img/image-20201021112638107.png)]

  • Controller 接口:
  • HttpRequestHandler 接口:
  • HttpServlet 接口:
  • @RequestMapping方法注解

可以看出 Handler 没有统一的接口,当dispatchServlet获取当对应的Handler之后如何调用呢?调用其哪个方法?这里有两种解决办法,**一是用instanceof 判断Handler 类型然后调用相关方法 。二是通过引入适配器实现,每个适配器实现对指定Handler的调用。**spring 采用后者。

HandlerAdapter详解

spring mvc 采用适配器模式来适配调用指定Handler,根据Handler的不同种类采用不同的Adapter,其Handler与 HandlerAdapter 对应关系如下:

Handler类别对应适配器描述
ControllerSimpleControllerHandlerAdapter标准控制器,返回ModelAndView
HttpRequestHandlerHttpRequestHandlerAdapter业务自行处理 请求,不需要通过modelAndView 转到视图
ServletSimpleServletHandlerAdapter基于标准的servlet 处理
HandlerMethodRequestMappingHandlerAdapter基于@requestMapping对应方法处理

HandlerAdapter 接口方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pqj1TVga-1662071432793)(https://gitee.com/onlycreator/draw/raw/master/img/image-20201020205308786.png)]

HandlerAdapter 接口结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tjEkzfDP-1662071432794)(https://gitee.com/onlycreator/draw/raw/master/img/image-20201020205312249.png)]

  • 演示基于Servlet 处理 SimpleServletHandlerAdapter
	<!-- 6 配置Servlet适配器 -->
	<bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>
	<!-- 6.演示servlet -->
	<bean id="/servlet" class="com.naixue.web.servlet.OneServlet"/>
public class OneServlet extends HttpServlet {
	private static final long serialVersionUID = 46587649263984732L;
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.getWriter().println("this is a servlet!");
	}
}

上述例子中当IOC 中实例化这些类之后 DispatcherServlet 就会通过
org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter() 方法查找对应handler的适配器 ,如果找不到就会报 如下异常 。

javax.servlet.ServletException: No adapter for handler [com.tuling.control.SimpleControl@3c06b5d5]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1198)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)

ViewResolver 与View 详解

找到应的Adapter 之后就会基于适配器调用业务处理,处理完之后业务方会返回一个ModelAndView ,在去查找对应的视图进行处理。其在org.springframework.web.servlet.DispatcherServlet#resolveViewName() 中遍历 viewResolvers 列表查找,如果找不到就会报一个 Could not resolve view with name 异常。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NxkEpiZF-1662071432795)(https://gitee.com/onlycreator/draw/raw/master/img/image-20201020213549824.png)]

BeanNameViewREsolver示例:
添加自定义视图:

public class MyView implements View {
	@Override
	public String getContentType() {
		return "text/html; charset=utf-8";
	}

	@Override
    public void render(Map<String, ?> model, HttpServletRequest
            request, HttpServletResponse response) throws Exception {
		Integer num = Integer.valueOf((String) model.get("num"));
		response.setHeader("Content-Type","text/html; charset=utf-8");
		response.getWriter().print("10进制num:"+num+"\n转\n16进制为:"+Integer.toHexString(num));
    }
}

视图解析器:

public class NXViewResolver implements ViewResolver, Ordered {
	private Integer order;

	@Override
	public View resolveViewName(String viewName, Locale locale) throws Exception {
		//根据视图名返回视图对象
		if (viewName.startsWith("nx:")) {
			return new MyView();
		}
		return null;
	}

	//实现Orderd接口,可以修改视图解析器的优先级
	@Override
	public int getOrder() {
		return this.order;
	}

	//改变视图解析器的优先级
	public void setOrder(Integer i) {
		this.order = i;
	}
}

配置视图解析器:

	<bean  name= "myView"  class="com.naixue.web.view.MyView"/>
	<!--自定义的视图解析器    value="1"数字越小优先级越高-->
	<bean class="com.naixue.web.view.NXViewResolver">
		<property name="order" value="1"></property>
	</bean>

修改视图跳转方法 :

public class ViewController implements Controller {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
		String num = request.getParameter("num");
		if (!StringUtils.isNumeric(num)) {
			throw new HttpServerErrorException(HttpStatus.BAD_REQUEST,"请输入num");
		}
		ModelAndView mv = new ModelAndView();
		mv.setViewName("nx:view");
		mv.addObject("num", num);
		return mv;
	}
}

配置Controller的bean

<bean name="/view" class="com.naixue.web.ViewController"/>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H2XDH1Y7-1662071432796)(https://gitee.com/onlycreator/draw/raw/master/img/image-20201021111403734.png)]

专栏目录

  1. 1-Spring架构源码分析-Spring源码搭建
  2. 2-Spring架构源码分析-SSM框架说明
  3. 3-Spring架构源码分析-spring体系
  4. 4-Spring架构源码分析-Spring IOC机制设计思想和源码解读
  5. 5-Spring架构源码分析-Spring IOC之 Spring 统一资源加载策略
  6. 6-Spring架构源码分析-IoC 之加载 BeanDefinition
  7. 7-Spring架构源码分析-IoC 之注册 BeanDefinitions
  8. 8-Spring架构源码分析-IoC 之解析Bean:解析 import 标签
  9. 9-Spring架构源码分析-IoC 之解析 bean 标签:开启解析进程
  10. 10-Spring架构源码分析-IoC 之解析 bean标签:BeanDefinition
  11. 11-Spring架构源码分析-IoC 之注册解析的 BeanDefinitions
  12. 12-Spring架构源码分析-IoC 之装载 BeanDefinitions 总结
  13. 13-Spring架构源码分析-IoC 之开启 Bean 的加载
  14. 14-Spring架构源码分析-IoC 之加载 Bean:总结
  15. 15-Spring架构源码分析-Spring代理与AOP
  16. 16-Spring AOP源码分析-@EnableAspectJAutoProxy和AspectJAutoProxyRegistrar
  17. 17-Spring AOP源码分析-AnnotationAwareAspectJAutoProxyCreator
  18. 18-Spring AOP源码分析-AOP与BeanPostProcessor处理器
  19. 19-Spring AOP源码分析-代理对象调用目标方法
  20. 20-spring mvc设计思想和源码解读-spring mvc 功能特性
  21. 21-mvc 体系结构源码详解
  22. 22-Spring MVC源码跟踪
  23. 23-Spring事务源码分析

相关文章:

  • 22-Spring MVC源码跟踪
  • 113:vue+openlayers 动态添加layer到layerGroup,并动态删除( 示例代码 )
  • ardupilot电机类直接的继承关系《2》
  • 如何将本地项目文件夹推到git上去
  • Windows开启路由转发功能
  • 翻译: 详细图解Transformer多头自注意力机制 Attention Is All You Need
  • LED驱动器 DC恒流电源板模块
  • H5画布绘制文本
  • 寻找协调器FindCoordinatorRequest请求流程
  • jsvmp-某乎 x-zes-96 算法还原
  • 迅速了解JDK线程池以及Spring线程池
  • 前缀和与查分(一维前缀和,二维前缀和(子矩阵的和)一维差分、二维差分(差分矩阵))
  • 2022年是SEO行业凋谢的一年
  • CDR插件开发之Addon插件006 - 初体验:通过C#代码用外挂方式操作CDR中的对象
  • 【2020.09.01】 新学期,新气象
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • CSS 专业技巧
  • JavaWeb(学习笔记二)
  • js对象的深浅拷贝
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • PV统计优化设计
  • Python爬虫--- 1.3 BS4库的解析器
  • Web设计流程优化:网页效果图设计新思路
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 欢迎参加第二届中国游戏开发者大会
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 前端自动化解决方案
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 微信开源mars源码分析1—上层samples分析
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (二)PySpark3:SparkSQL编程
  • (二十四)Flask之flask-session组件
  • (翻译)terry crowley: 写给程序员
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .net 7 上传文件踩坑
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET Framework杂记
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .netcore 获取appsettings