SpringMVC 执行流程 记录一下

6 篇文章 0 订阅
5 篇文章 0 订阅

讲道理,源码如果想完全搞懂真的很难,毕竟不是站在作者的角度去思考的,只能去理解一些浅显的思想和一些地方采用了设计模式。从源码中可以看出,为什么明明一行代码就可以搞定的CURD,要引入那么多接口、抽象类,以及各种设计模式??

从以前有一些工作经验之后,觉得springmvc的思想就是,有一个前端控制器去结合tomcat的统一监听入口做统一拦截,之后mvc作为任务的分发利用反射处理之后返回数据,但是万万没想到= =竟然这么复杂,有机会一定会更深入去了解,先继续往后学吧

SpringMVC 工作流程

mvc工作流程,客户端发送请求,tomcat监听端口,经过tomcat将request进行解析封装成 Java可识别的servlet,之后通过配置中的url请求地址,找到mvc定义的规范(dispatcherServlet一个普通的实现了Servlet规范的类),之后通过前端控制器 + url请求路径,找到对应的处理器类(mvc自己封装了处理器类信息,如requestmapping中的value值,还有对应的处理器类),随后基于mvc的执行链(handler)找到对应的所需的处理适配器,用于真正的调用方法(基于反射,期间还通过request请求信息 通过参数解析器找到方法所需的全部参数,遍历判断类型如果是一般配型直接赋值,如果是model或者map则直接从隐含类型的缓存中读取,如果是自定义类型那么首先会判断model隐含类型中是否对应的保存了这个自定义对象如果没有获取到,那么会自己new一个进行返回),随后得到结果,mvc会自动封装成modelandview交给视图解析器进行解析数据转发和页面跳转。

细节:mvc 中 有一个对接 tomcat的接口:dispatchServlet

dispatchServlet:

是一个普通的 实现了 Java定义Servlet规范的 前端控制器,主要用于统一处理客户端请求。

当接受到request 之后,会基于request最终调用doService,doService中调用 doDispatch(),

image-20210523160619669

验证是否是文件上传请求,如果是文件上传请求如果是文件上传请求转为文件servlet,否则仍然是当前请求信息。

随后基于request中的信息(其中包括url,port,网络协议等等)

mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
   /**
    * 如果没有找到,抛出异常
    */
   noHandlerFound(processedRequest, response);
   return;
}

基于 request请求信息,解析出所需要的 mappedHandler (处理器类),里面保存了一些处理器对象信息,如果没有找到直接抛出异常:404。

需要注意的是:getHandler() 中找到 处理器类的流程

image-20210523161453889

@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

image-20210523161518288

会通过:handlerMappings 遍历 里面的 handlerMapping 对象来获取 映射地址指向的 处理器类(handler),这个handler并非真正操作的方法,可以理解为bean对象。

那么这个handlerMappings 从哪里来的呢?

而实现了servlet 接口的 dispatcherServlet,会有一个初始化的接口。

/**
	 * This implementation calls {@link #initStrategies}.
	 */
	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

而最终指向了 initStrategies(context);

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
    // 我在这里,我是handlerMappings的初始化方法
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

这里面初始化了一系列的东西,可以称为SpringMVC的九大组件,现在只关注 HandlerMappings(),我们点进去。

private void initHandlerMappings(ApplicationContext context) {
		// 置为null
		this.handlerMappings = null;

		// 默认检测所有,否则只检测 bean名称为 handlerMapping的一个
		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			// 找到全部的handlerMappings
			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.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
            // 只找一个名称为handlerMapping的对象,并且尝试强转,如果转失败了,那么会报错
			try {
				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.
    // 如果一个都没有找到,那么会采用默认的策略,至少保证该容器中有一个hanldermapping
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

// 默认检测所有,否则只检测 bean名称为 handlerMapping的一个

// 从bean中找到全部的handlerMappings

// 如果 找到了至少一个,那么会排个顺序

如果不是找到全部的hanlderMappings 只是找到一个bean名称为 handlerMapping的对象

// 只找一个名称为handlerMapping的对象,并且尝试强转,如果转失败了,那么会报错

// 如果一个都没有找到,那么会采用默认的策略,至少保证该容器中有一个hanldermapping

默认实现使用“ DispatcherServlet.properties”文件(与DispatcherServlet类位于同一包中)来确定类名称。 它通过上下文的BeanFactory实例化策略对象

@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

handlerMappings 是有序的,所以当找到了就会立刻返回后续的不会继续执行,排序靠后的就会被前面的handler给覆盖??

HandlerExecutionChain 执行链

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

随后通过 找到的处理器对象,mappedHandler.getHandler() 其实获取到的就是 对应的contraoller(handler) 类对象,随后通过类对象获取到指定的方法调用适配器。HandlerAdapter()

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    // handlerAdapters 来源: initHandlerAdapters(context);
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

之后通过处理器类,找到适合的处理器适配器,如果找不到那么就会报错。

image-20210523164501703

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception

img

能力不够,只能到这了= =

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值