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事务源码分析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xianghan收藏册

极简精品作,一分也是一份鼓励哦

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

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

打赏作者

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

抵扣说明:

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

余额充值