SpringMVC源码学习(五)---解析处理适配器HandlerAdapter

SpringMVC源码分析 专栏收录该内容
7 篇文章 0 订阅

一. HandlerAdapter继承关系图

在这里插入图片描述

二. DispatcherServlet类中的getHandlerAdapter()方法

在这里插入图片描述

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter ha : this.handlerAdapters) {
				if (logger.isTraceEnabled()) {
					logger.trace("Testing handler adapter [" + ha + "]");
				}
				//如果该适配器支持当前handler, 则直接返回该适配器
				if (ha.supports(handler)) {
					return ha;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

三. HandlerAdapter接口

在这里插入图片描述

//映射适配器
public interface HandlerAdapter {

	//查看当前适配器是否支持该处理器
	boolean supports(Object handler);

	//处理请求
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	long getLastModified(HttpServletRequest request, Object handler);

}

四. 子类HttpRequestHandlerAdapter源码解析

在这里插入图片描述

五. 子类SimpleControllerHandlerAdapter源码分析

在这里插入图片描述

六. 子类SimpleServletHandlerAdapter

在这里插入图片描述

七. 子类AbstractHandlerMethodAdapter

在这里插入图片描述

八. RequestMappingHandlerAdapter子类

①. handleInternal() 方法

在这里插入图片描述

	@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
		// 1.检测当前请求,验证请求方法合法性和session合法性
		checkRequest(request);

		// 2.根据synchronizeOnSession值判断,当前请求是否需串行化访问。
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				// 获取最佳互斥锁,即同步当前回话对象;如未能获取到互斥锁,将返回HttpSession对象本身
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// 即无最佳互斥锁,也未能获取到HttpSession,则当前回话无需串行化访问
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// 3.相应信息不包含Cache-Control
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}
		return mav;
	}

②. invokeHandlerMethod() 方法

在这里插入图片描述

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

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			//WebDataBinderFactory --> 工厂类,为目标对象创建一个WebDataBinder实例
			// 1.WebDataBinder继承了DataBinder类,为web请求提供了参数绑定服务
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

			// 获取ModelFactory:
			// 2.ModelFactory可以协助控制器在调用方法之前初始化模型,并在调用之后更新模型
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			// 创建ServletInvocableHandlerMethod对象
			// 3.ServletInvocableHandlerMethod继承并扩展了InvocableHandlerMethod
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			// 4.尝试绑定参数、返回值解析器
			if (this.argumentResolvers != null) {
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers != null) {
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			// 5.创建ModelAndViewContainer,并初始化Model对象
			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			// 6.异步请求相关
			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);

			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

			if (asyncManager.hasConcurrentResult()) {
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				asyncManager.clearConcurrentResult();
				if (logger.isDebugEnabled()) {
					logger.debug("Found concurrent result value [" + result + "]");
				}
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

			// 7.调用Controller中的具体方法并处理返回值
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

			// 8.返回ModelAndView对象
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			// 完成请求后续处理,并将当前请求置为未激活
			webRequest.requestCompleted();
		}
	}

③.getDataBinderFactory() 方法

在这里插入图片描述

	private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
		// 1.获取handlerType,即目标类
		Class<?> handlerType = handlerMethod.getBeanType();
		// 2.优先尝试从缓存中获取对应的InitBinder方法
		Set<Method> methods = this.initBinderCache.get(handlerType);
		// 如未能从缓存中获取,则根据handlerType对应的类,去类中查找所有标注了@InitBinder注解的方法,并将其缓存
		if (methods == null) {
			methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
			this.initBinderCache.put(handlerType, methods);
		}
		// 3.从标注了@ControllerAdvice类中寻找InitBinder方法,并优先为其创建InvocableHandlerMethod对象
		List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
		// Global methods first
		this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
			if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
				Object bean = controllerAdviceBean.resolveBean();
				for (Method method : methodSet) {
					initBinderMethods.add(createInitBinderMethod(bean, method));
				}
			}
		});
		// 4.为普通的InitBinder创建InvocableHandlerMethod对象
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			initBinderMethods.add(createInitBinderMethod(bean, method));
		}
		// 5.创建InitBinderDataBinderFactory对象
		return createDataBinderFactory(initBinderMethods);
	}

④. getModelFactory()方法

在这里插入图片描述

	private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
		// 1.处理@SessionAttributes注解
		SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
		Class<?> handlerType = handlerMethod.getBeanType();
		// 2.处理@ModelAttribute注解
		Set<Method> methods = this.modelAttributeCache.get(handlerType);
		if (methods == null) {
			methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
			this.modelAttributeCache.put(handlerType, methods);
		}
		List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
		// 3.优先处理全局@ModelAttribute注解的方法,例如被@ControllerAdvice标注的类中存在被@ModelAttribute注解的方法,则优先处理
		this.modelAttributeAdviceCache.forEach((clazz, methodSet) -> {
			if (clazz.isApplicableToBeanType(handlerType)) {
				Object bean = clazz.resolveBean();
				for (Method method : methodSet) {
					attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
				}
			}
		});
		// 4.循环所有标注了@ModelAttribute注解的方法,并创建InvocableHandlerMethod对象
		// InvocableHandlerMethod:负责具体的HandlerMethod的调用、参数解析等工作
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
		}
		// 5.返回ModelFactory对象
		// ModelFactory:协助在控制器方法调用之前初始化模型,并在调用之后更新它。
		return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
	}

⑤. ModelFactory类的initModel初始化

在这里插入图片描述

	public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
			throws Exception {

		// 1.解析并合并@SessionAttributes注解
		Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
		container.mergeAttributes(sessionAttributes);
		// 2.调用被@ModelAttribute注解的方法
		invokeModelAttributeMethods(request, container);

		// 3.查找标注了@ModelAttribute、@SessionAttributes的方法参数,确保其解析过程中不会发生异常
		for (String name : findSessionAttributeArguments(handlerMethod)) {
			if (!container.containsAttribute(name)) {
				Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
				if (value == null) {
					throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
				}
				container.addAttribute(name, value);
			}
		}
	}

九. DispatcherServlet类中的initHandlerAdapters()方法

适配器被加载到容器中
在这里插入图片描述

十. DispatcherServlet类中的initStrategies()方法

  • initStrategies()方法的主要作用, 就是从Spring容器中获取到已经注册的各种Bean,也就是SpringMVC需要的各种组件对象, 获取到指定的组件实例后, 将其注册到SpringMVC的各种子容器中, 以便后面进行获取
  • Spring在解析 <mvc:annotation-driven /> 标签时会帮我们注入 RequestMappingHandlerAdapter 、HttpRequestHandlerAdapter 和 SimpleControllerHandlerAdapter 这三个适配器,需要注意下不要手动重复注入。
  • 当没有配置 <mvc:annotation-driven /> 标签时容器在初始化的时候检测到会自动注入 RequestMappingHandlerAdapter 、HttpRequestHandlerAdapter 和 SimpleControllerHandlerAdapter 这三个适配器

在这里插入图片描述

	protected void initStrategies(ApplicationContext context) {
		// 1.初始化MultipartResolver 解析multi-part的传输请求
		initMultipartResolver(context);
		// 2.初始化LocaleResolver 地区解析器 和 地区上下文解析器
		initLocaleResolver(context);
		// 3.初始化ThemeResolver 主题解析器
		initThemeResolver(context);
		// 4.初始化HandlerMappings 	处理器异常解析器
		initHandlerMappings(context);
		// 5.初始化HandlerAdapters 处理器适配器
		initHandlerAdapters(context);
		// 6.初始化HandlerExceptionResolvers 处理器异常解析器。
		initHandlerExceptionResolvers(context);
		// 7.初始化RequestToViewNameTranslator
		initRequestToViewNameTranslator(context);
		// 8.初始化ViewResolvers 视图解析器
		initViewResolvers(context);
		// 9.初始化FlashMapManager 	FlashMap管理器
		initFlashMapManager(context);
	}

处理适配器解析完成

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值