Spring MVC源码剖析

Spring MVC简介

MVC体系结构

  • 三层架构
    我们的开发架构一般都是基于两种形式,一种是C/S架构(客户端/服务器),另一种是B/S架构(浏览器/服务器)。在JavaEE开发中,几乎全部都是基于B/S架构的开发。在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。
  • MVC设计模式
    MVC全名是Model View Controller,是 模型(Model)-视图(View)-控制器(Controller)的缩写,是一种用于设计创建Web应用程序表现层的模式。MVC中每个部分各司其职:
    • Model:模型包含业务模型和数据模型,数据模型用于封装数据,业务模型用于处理业务。
    • View:通常指jsp或者html,用于展示数据,通常视图时依据数据模型创建的
    • Controller:是应用程序中处理用户交互的部分,用于处理程序逻辑的。
      MVC提倡:每一层只编写自己的东西,不编写任何其他代码;分层是为了解耦,解耦是为了维护方便和分工协作。

Spring MVC是什么

Spring MVC全面是Spring Web MVC,是一种基于java实现的MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品。

Spring MVC工作流程

Spring MVC 请求处理流程

SpringMVC请求流程图
流程说明

  • 第一步:用户发送请求至前端控制器DispatcherServlet
  • 第二部:DispathcerServlet收到请求调用HanlderMapping处理器映射器
  • 第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),生成处理器对象及处理器拦截器一并返回DispatcherServlet
  • 第四步:DispathcerServlet调用HandlerAdapter处理器适配器去调用Handler
  • 第五步:处理器适配器执行Hanlder
  • 第六步:Hanlder执行完成给处理器适配器返回ModelAndView
  • 第七步:处理器适配器向前端控制器返回ModelAndView
  • 第八步:前端控制器请求ViewResolver视图解析器,解析视图
  • 第九步:视图解析器解析完毕返回View视图
  • 第十步:前端控制器进行视图渲染,将模型数据填充到request中
  • 第十一步:前端控制器向用户响应结果

Spring MVC九大组件

  • HanlderMapping(处理器映射器)
    HandlerMapping是用来查找Hanlder处理器的
  • HandlerAdapter(处理器适配器)
    HandlerAdapter是一个适配器,适配具体处理请求的Hanlder
  • HandlerExceptionResolver(处理器异常解析器)
    HandlerExceptionResolver是用于处理Handler产生的异常情况
  • ViewResolver(视图解析器)
    ViewResolver是视图解析器,用于找到渲染所用的模板和所用视图并填入数据。
  • RequesetToViewNameTranslator(请求-视图名称转换器)
    RequesetToViewNameTranslator作用是从请求中获取VIewName。ViewResolver是根据ViewName查找View,若Hanlder处理完成之后没有设置View,也没有设置ViewName,那么就是通过该组件从请求中查找ViewName
  • LocalResolver(本地语言环境解析器)
    LocalResolver是支持国际化的组件
  • ThemeResolver(主题解析器)
    ThemResolver组件是用来解析主题的,即各种样式、图片等
  • MultipartResolver(多部件解析器,文件上传)
    MultipartResolver适用于上传请求,通过将普通请求包装成MultipartHttpServletRequest来实现。
  • FlashMapManager(FlashMap管理器)
    FlashMap用于重定向时的参数传递。

Spring MVC源码剖析

前端控制器DispatcherServlet继承结构

在这里插入图片描述
在这里插入图片描述

重要时机点分析

  • Hanlder方法的执行时机
    在controller的方法中打断点,观察调用栈
    在这里插入图片描述
    doDispatch方法中1040行完成handle方法调用
  • Spring MVC处理请求的流程为org.springframework.web.servlet.DispatcherServlet#doDispatch方法的执行过程,其中步骤2、3、4、5是核心步骤
    1、调⽤getHandler()获取到能够处理当前请求的执⾏链 HandlerExecutionChain(Handler+拦截器)
    2、⽤getHandlerAdapter();获取能够执⾏1中Handler的适配器
    3、适配器调⽤Handler执⾏ha.handle(总会返回⼀个ModelAndView对象)
    4、调⽤processDispatchResult()⽅法完成视图渲染跳转

核心步骤getHandler方法剖析

在DispatcherSerlvet调用getHanlder方法处打断点
在这里插入图片描述
进入getHandler方法
在这里插入图片描述
遍历handlerMappings,获取能够处理当前请求的执行链

核心步骤getHandlerAdapter方法剖析

如getHandler一样,在调用getHandlerAdapter方法处打断点
在这里插入图片描述
进入getHandlerAdapter方法

遍历handlerAdapters,获取支持处理当前Handler的Adapter

核心步骤ha.handle方法剖析

在调用Handler的handle方法处打断点
在这里插入图片描述
进入方法查看具体执行流程
在这里插入图片描述
适配具体Handler
在这里插入图片描述
执行方法
在这里插入图片描述

在这里插入图片描述

核心步骤processDispatchResult方法剖析

如上述相同步骤,观察执行过程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
视图解析器解析处View视图对象
在这里插入图片描述
在解析出View视图对象的过程中,会判断是否重定向,是否转发等,不同情况封装不同的View实现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解析出View视图对象的过程中,要将逻辑视图名解析为物理视图名
在这里插入图片描述
封装View视图对象之后,调用View对象的render方法
在这里插入图片描述
渲染数据
在这里插入图片描述
把modelMap中的数据暴露到request域中
在这里插入图片描述
将数据设置到请求域中
在这里插入图片描述

Spring MVC九大组件初始化

  • 在DispatcherServlet中定义了九个属性,每一个属性都对应一种组件
    /** Well-known name for the MultipartResolver object in the bean factory for this namespace. */
    // 多部件解析器
	public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";

	/** Well-known name for the LocaleResolver object in the bean factory for this namespace. */
	// 区域化(国际化)解析器
	public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

	/** Well-known name for the ThemeResolver object in the bean factory for this namespace. */
	// 主题解析器
	public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";

	/**
	 * Well-known name for the HandlerMapping object in the bean factory for this namespace.
	 * Only used when "detectAllHandlerMappings" is turned off.
	 * @see #setDetectAllHandlerMappings
	 */
	 // 处理器映射器
	public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

	/**
	 * Well-known name for the HandlerAdapter object in the bean factory for this namespace.
	 * Only used when "detectAllHandlerAdapters" is turned off.
	 * @see #setDetectAllHandlerAdapters
	 */
	 // 处理器适配器
	public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";

	/**
	 * Well-known name for the HandlerExceptionResolver object in the bean factory for this namespace.
	 * Only used when "detectAllHandlerExceptionResolvers" is turned off.
	 * @see #setDetectAllHandlerExceptionResolvers
	 */
	 // 异常解析器
	public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";

	/**
	 * Well-known name for the RequestToViewNameTranslator object in the bean factory for this namespace.
	 */
	 // 默认视图名转换器
	public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";

	/**
	 * Well-known name for the ViewResolver object in the bean factory for this namespace.
	 * Only used when "detectAllViewResolvers" is turned off.
	 * @see #setDetectAllViewResolvers
	 */
	 // 视图解析器
	public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";

	/**
	 * Well-known name for the FlashMapManager object in the bean factory for this namespace.
	 */
	 // flash属性管理组件
	public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";

九大组件都是定义类接口,接口是定义了规范,我们可以实现自己的各种组件

  • 九大组件的初始化时机
/**
	 * This implementation calls {@link #initStrategies}.
	 */
	 // 该方法调用了初始化策略,初始化了九大组件
	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	/**
	 * Initialize the strategy objects that this servlet uses.
	 * <p>May be overridden in subclasses in order to initialize further strategy objects.
	 */
	 // 分别调用各个组件初始化方法进行初始化
	protected void initStrategies(ApplicationContext context) {
		//初始化多部件解析器组件(多用于文件上传)
		initMultipartResolver(context);
		// 初始化本地语言环境
		initLocaleResolver(context);
		// 初始化主题处理器
		initThemeResolver(context);
		// 初始化处理器映射器
		initHandlerMappings(context);
		// 初始化处理器适配器
		initHandlerAdapters(context);
		// 初始化处理器异常解析器
		initHandlerExceptionResolvers(context);
		// 处理请求-视图名称转换器
		initRequestToViewNameTranslator(context);
		// 处理视图解析器
		initViewResolvers(context);
		// 初始化FlashMap管理器
		initFlashMapManager(context);
	}
  • 观察其中一个组件initHandlerMappings(conetext)
/**
	 * Initialize the HandlerMappings used by this class.
	 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
	 * we default to BeanNameUrlHandlerMapping.
	 */
	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			// 按照HanlderMapping.class类型去IoC容器中找到所有的HandlerMapping
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				// 对HandlerMapping进行排序				
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				// 否则在IoC容器中按照固定名称Id(handlerMapping)去找
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		// 确保至少有一个HandlerMapping存在
		// 否则按照默认策略生成
		if (this.handlerMappings == null) {
			// 按照默认方式实例化生成HanlderMapping
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}
  • 如果按照类型和按照固定Id从IoC容器中找不到对应组件,则会按默认策略进行注册初始化,根据getDefaultStrategies方法中逻辑,默认策略在DispatcherServlet.properties文件中配置
/**
	 * Create a List of default strategy objects for the given strategy interface.
	 * <p>The default implementation uses the "DispatcherServlet.properties" file (in the same
	 * package as the DispatcherServlet class) to determine the class names. It instantiates
	 * the strategy objects through the context's BeanFactory.
	 * @param context the current WebApplicationContext
	 * @param strategyInterface the strategy interface
	 * @return the List of corresponding strategy objects
	 */
	@SuppressWarnings("unchecked")
	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		// DispatcherServlet.properties
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
							"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
							className + "] for interface [" + key + "]", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<>();
		}
	}
  • DispatcherServlet.properties
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

文件中包含了八个默认组件的默认实现,其中多部件解析器的初始化必须按照id注册对象(multipartResolver)

// 方法没有去注册默认多部件解析器
private void initMultipartResolver(ApplicationContext context) {
		try {
			// 通过指定的id从IoC容器中取出对象
			this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Detected " + this.multipartResolver);
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Default is no multipart resolver.
			this.multipartResolver = null;
			if (logger.isTraceEnabled()) {
				logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
			}
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值