执行目标方法RequestMappingHandlerAdapter#invokeHandlerMethod原理

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod( request, response, handlerMethod){
	// 封装req,resp对象
	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	// 创建用于数据绑定的工厂用于对参数进行转换
	WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);{
		// 获取bean的类型
		Class<?> handlerType = handlerMethod.getBeanType();
		// 查看这个bean中是否已经缓存过添加了@InitBinder的注解,只有找过一次的才会有
		Set<Method> methods = this.initBinderCache.get(handlerType);
		// 没有被缓存
		if (methods == null) {
			// 找bean中的MethodFilter INIT_BINDER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);方法
			methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
			// 缓存起来,这里是针对单个Controller添加了@InitBinder的方法,只能作用在Controller中
			this.initBinderCache.put(handlerType, methods);
		}
		// 将添加了@InitBinder的方法封装成InvocableHandlerMethod对象
		List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
		// 找全局的@InitBinder方法,在@ControllerAdvice标注了的就是全局的
		this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
			if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
				Object bean = controllerAdviceBean.resolveBean();
				for (Method method : methodSet) {
					// createInitBinderMethod,将method封装成InvocableHandlerMethod对象
					initBinderMethods.add(createInitBinderMethod(bean, method));{
						// 封装成HandlerMethod对象
						InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
						// 设置对于InitBinder方法的参数解析器,初始化HanderAdapter的时候就保存了一些默认的
						if (this.initBinderArgumentResolvers != null) {
							// 给方法设置参数解析器
							binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
						}
						// 创建DefaultDataBinderFactory对象,并设置到方法里
						binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
						// 设置参数名称的解析器
						binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
						return binderMethod;
					}
				}
			}
		});
		// 合并上面Controller私有的InitBinder方法
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			initBinderMethods.add(createInitBinderMethod(bean, method));
		}
		// 创建DataBinderFactory,用于参数绑定的
		return createDataBinderFactory(initBinderMethods);{
			/// 创建ServletRequestDataBinderFactory对象
			return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
		}
	}
	ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);{
		// 获取处理SessionAttributes注解的处理器
		SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);{
			return this.sessionAttributesHandlerCache.computeIfAbsent(handlerMethod.getBeanType(),
				type -> new SessionAttributesHandler(type, this.sessionAttributeStore){
							this.sessionAttributeStore = sessionAttributeStore;
							// 保存属性名称
							SessionAttributes ann = AnnotatedElementUtils.findMergedAnnotation(handlerType, SessionAttributes.class);
							if (ann != null) {
								Collections.addAll(this.attributeNames, ann.names());
								Collections.addAll(this.attributeTypes, ann.types());
							}
							this.knownAttributeNames.addAll(this.attributeNames);
				});
		}
		// 获取bean的类型
		Class<?> handlerType = handlerMethod.getBeanType();
		// 看是否已经被缓存过,因为这种只需要第一次处理才要去找,后面直接拿缓存
		Set<Method> methods = this.modelAttributeCache.get(handlerType);
		if (methods == null) {
			// MethodFilter MODEL_ATTRIBUTE_METHODS = method -> (!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));
			// 找Controller标注了ModelAttribute注解,但是不能有RequestMapping注解的方法
			methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
			// 缓存起来
			this.modelAttributeCache.put(handlerType, methods);
		}

		// 将添加了@ModelAttribute的方法封装成InvocableHandlerMethod对象
		List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
		// 找全局的@ModelAttribute,在@ControllerAdvice标注了的就是全局的
		this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
			// 遍历所有的AdviceBean
			if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
				Object bean = controllerAdviceBean.resolveBean();
				for (Method method : methodSet) {
				    // createModelAttributeMethod,将method封装成InvocableHandlerMethod对象
					attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));{
						// 封装成HandlerMethod对象
						InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
						// 设置参数解析器
						if (this.argumentResolvers != null) {
							attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
						}
						// 设置参数名称的解析器
						attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
						// 设置数据绑定的工厂
						attrMethod.setDataBinderFactory(factory);
						return attrMethod;
					}
				}
			}
		});
		// 合并上面Controller私有的ModelAttribute方法
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
		}
		// 返回Model工厂,用于处理数据的,处理ModelAttribute注解,从Model中获取数据或者返回数据放入model中
		// 如果ModelAttribute加在方法上,返回值就会作为参数放入Model中,默认名称就为返回值的类型首字母小写,也可以指定名称
		// 如果ModelAttribute加在参数上,就表示该参数的值依赖Model中的数据,默认名称就为参数的类型首字母小写,也可以指定名称
		return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);{
			if (handlerMethods != null) {
				// 遍历所有的handlerMethod
				for (InvocableHandlerMethod handlerMethod : handlerMethods) {
					// 将方法封装成ModelMethod对象,持有handlerMethod
					this.modelMethods.add(new ModelMethod(handlerMethod){
						// 创建ModelMethod对象
						this.handlerMethod = handlerMethod;
						// 获取handlerMethod的参数
						// 同一个方法多个参数都可能被标记了ModelAttribute
						for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
							// 如果参数上含有ModelAttribute,表示当前方法依赖于Model中的数据
							if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
								// 保存当前方法参数依赖Model的参数,默认为类型的首字母小写,如果没有给定名称的话
								this.dependencies.add(getNameForParameter(parameter));
							}
						}
					});
				}
			}
			this.dataBinderFactory = binderFactory;
			this.sessionAttributesHandler = attributeHandler;
		}
	}
	// 再封装一下HandlerMethod,变成可执行的HandlerMethod,内部包含解析返回值处理器,returnValueHandlers,parameterNameDiscoverer,参数解析器,resolvers,数据绑定dataBinderFactory
	ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
	// 设置参数解析器
	if (this.argumentResolvers != null) {
		invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
	}
	// 设置返回值处理器
	if (this.returnValueHandlers != null) {
		invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
	}
	// 设置数据绑定的工厂
	invocableMethod.setDataBinderFactory(binderFactory);
	// 设置参数名称的解析器
	invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
	// 构建一个执行容器,执行过程中的数据都保存到这个容器中,例如,视图,Model数据,状态码,请求是否处理完成等等
	ModelAndViewContainer mavContainer = new ModelAndViewContainer();
	// 将flashMap中的数据转移进来
	mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
	modelFactory.initModel(webRequest, mavContainer, invocableMethod);{
		// 使用上面创建的sessionAttributesHandler,获取处理SessionAttributes注解的处理器
		// 就是将SessionAttributes中的名称一一从Session域中提取数据,将Key-Value保存
		Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
		// 保存到mavContainer中,与自身的Model数据合并
		container.mergeAttributes(sessionAttributes);
		// 执行标注了ModelAttributeMethod的方法
		invokeModelAttributeMethods(request, container);{
			// 如果存在这种方法,标注了ModelAttribute的方法
			while (!this.modelMethods.isEmpty()) {
				//
				InvocableHandlerMethod modelMethod = getNextModelMethod(container){
														// 遍历所有modelMethods方法
														for (ModelMethod modelMethod : this.modelMethods) {
															// 在上面有说明过,在创建ModelMethod的时候,会将该方法中,参数中含有ModelAttribute的参数名称保存下来
															// 而且,同一个方法多个参数都可能被标记了ModelAttribute
															// 如果为true,说明当前mvcContainer中,包含了当前HandlerMethod所有依赖的参数数据
															if (modelMethod.checkDependencies(container)) {
																	// 将这个方法删除,执行后就不需要了
																	this.modelMethods.remove(modelMethod);
																	// 返回执行
																	return modelMethod;
																}
															}
															// 如果上面判断不通过,那么就会直接获取第一个来执行
															// 如果没有ModelAttribute需要参数,就根据参数类型根据无参构造创建默认的对象赋值,这一步是在invokeForRequest完成的
															ModelMethod modelMethod = this.modelMethods.get(0);
															// 将这个方法删除,执行后就不需要了
															this.modelMethods.remove(modelMethod);
															return modelMethod;
													}
													.getHandlerMethod();
				// 获取方法上的注解ModelAttribute
				ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
				// 因为进这里,说明方法中一定有这个注解,才会被扫描
				Assert.state(ann != null, "No ModelAttribute annotation");
				// 如果Model中已经包含了此属性,就不需要执行ModelAttribute的方法返回对象,直接从Model中获取
				if (container.containsAttribute(ann.name())) {
					// 还可以设置当前属性是否可以被绑定,如果不能,会被忽略
					if (!ann.binding()) {
						container.setBindingDisabled(ann.name());
					}
					continue;
				}
				// 执行目标方法
				Object returnValue = modelMethod.invokeForRequest(request, container);
				if (modelMethod.isVoid()) {
					// 方法没有返回值,不需要做任何处理
					continue;
				}
				// 获取返回值的ModelAttribute对应的属性,如果标注了name属性,或者没有标注(使用返回值类型的首字母小写),然后将返回值存入按照name-value存入Model中
				String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
				// 还可以设置当前属性是否可以被绑定,如果不能,会被忽略
				if (!ann.binding()) {
					container.setBindingDisabled(returnValueName);
				}
				// 如果Model中不包含这个属性
				if (!container.containsAttribute(returnValueName)) {
					// 将属性存入Model中
					container.addAttribute(returnValueName, returnValue);
				}
			}
		}
		// 找到方法中有SessionAttribute的参数,
		for (String name : findSessionAttributeArguments(handlerMethod){
								List<String> result = new ArrayList<>();
								// 找到方法中有@ModelAttribute的参数
								for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
									if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
										// 获取ModelAttribute的属性名称,要么指定,要么是参数类型首字母小写
										String name = getNameForParameter(parameter);
										Class<?> paramType = parameter.getParameterType();
										// 判断之前SessionAttributes中添加的参数名称包不包含标注了@ModelAttribute的参数名,或者是相同类型的数据: 例如@SessionAttributes({"a","b"}) @ModelAttribute("b")
										// 如果包含,那么要将session中的值放在@ModelAttribute中的参数中
										if (this.sessionAttributesHandler.isHandlerSessionAttribute(name, paramType){
																				// getModelFactory的时候,就已经将类中包含的SessionAttributes注解中的key,保存到attributeNames中和knownAttributeNames中
																				// 如果包含,那么要将session中的值放在@ModelAttribute中的参数中
																				if (this.attributeNames.contains(attributeName) || this.attributeTypes.contains(attributeType)) {
																					// 这个就是已知需要从session获取数据的所有名称
																					this.knownAttributeNames.add(attributeName);
																					return true;
																				}
																			})
										{
											// 符合从session中获取数据的标注了@ModelAttribute的名称
											result.add(name);
										}
									}
								}
								return result;
							}) {
			// 如果Model中不包含这个属性,因为这个name就是上面找到的需要从session获取数据的name
			if (!container.containsAttribute(name)) {
				// 使用上面创建的sessionAttributesHandler,获取处理SessionAttributes注解的处理器
				// 就是将SessionAttributes中的名称一一从Session域中提取数据,将Key-Value保存
				Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
				// 如果Session不存在这个值,就要报错
				if (value == null) {
					throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
				}
				// 保存到Modle中
				container.addAttribute(name, value);
			}
		}
	}
	// 设置是否忽略默认的模型重定向的时候,默认Model类型BindingAwareModelMap,重定向模型是ModelMap
	mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

	// 创建异步请求参数,下面是处理异步请求的设置
	AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
	// 设置超时时间
	asyncWebRequest.setTimeout(this.asyncRequestTimeout);
	// 获取异步请求管理器
	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
	// 设置线程池
	asyncManager.setTaskExecutor(this.taskExecutor);
	// 设置请求对象,封装了req,resp
	asyncManager.setAsyncWebRequest(asyncWebRequest);
	// 设置一个处理返回Callable接口的拦截器
	asyncManager.registerCallableInterceptors(this.callableInterceptors);
	// 设置一个处理返回DeferredResult的拦截器
	asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
	// 判断一下请求返回结果是不是异步相关的结果,同步的请求默认都为false,异步的时候会将默认的返回值改掉
	if (asyncManager.hasConcurrentResult(){
						// 默认的返回值RESULT_NONE,如果是异步的请求,那么返回值会将RESULT_NONE改掉
						return (this.concurrentResult != RESULT_NONE);
					}) {
			// 获取异步的执行结果
			Object result = asyncManager.getConcurrentResult();
			// 获取mavContainer,异步的时候是存入到getConcurrentResultContext中
			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
			// 清理结果
			asyncManager.clearConcurrentResult();
			// 包装异步的结果,因为异步的结果返回的不是真实的结果,而是Callable或者DeferredResult,包装成ConcurrentResultHandlerMethod来执行目标方法
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}
		// 执行ConcurrentResultHandlerMethod的方法,详见执行目标方法-ServletInvocableHandlerMethod#invokeAndHandle原理
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		// 如果返回的实异步的方法,直接返回
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}
		// 返回一个ModelAndView对象
		return getModelAndView(mavContainer, modelFactory, webRequest);{
			// 更新一下mavContainer中Model的数据
			modelFactory.updateModel(webRequest, mavContainer);{
				ModelMap defaultModel = container.getDefaultModel();
				// 如果session相关的逻辑已经完成,清除session的值
				if (container.getSessionStatus().isComplete()){
					this.sessionAttributesHandler.cleanupAttributes(request);
				}
				else {
					// 如果还没有处理完成,将模型中的数据一一保存到session中
					this.sessionAttributesHandler.storeAttributes(request, defaultModel);
				}
				// 如果当前请求未处理完成,并且当前请求是默认的模型数据(不是重定向的Model),因为有普通的和重定向的两种Model,当重定向的时候,model!=defualtModel
				if (!container.isRequestHandled() && container.getModel() == defaultModel) {
					// 将BindingResult中存入Model中,如果BindingResult在执行的过程中记录有一些错误信息,参数校验信息
					updateBindingResult(request, defaultModel);{
						List<String> keyNames = new ArrayList<>(model.keySet());
						for (String name : keyNames) {
							Object value = model.get(name);
							// String MODEL_KEY_PREFIX = BindingResult.class.getName() + ".";
							// 如果model中存在的属性值是
							if (value != null && isBindingCandidate(name, value){
													// 如果是bingResult的属性,就不需要添加了
													if (attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
														return false;
													}
													// 原理会话中的属性,是需要的
													if (this.sessionAttributesHandler.isHandlerSessionAttribute(attributeName, value.getClass())) {
														return true;
													}
													// 不能是数组,不能是集合,不能是Map,不能是简单类型的对象,只能是普通单一对象,返回true
													return (!value.getClass().isArray() && !(value instanceof Collection) &&
														!(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass()));
												}) {
								// 获取默认的Key
								String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name;
								// Modle中不存在的话
								if (!model.containsAttribute(bindingResultKey)) {
									// 创建DataBinder对象
									WebDataBinder dataBinder = this.dataBinderFactory.createBinder(request, value, name);
									// 将绑定结果放在Model中,这样就保证了每一个每一个Model中的属性,都对应了一个BindingResult
									model.put(bindingResultKey, dataBinder.getBindingResult());
								}
							}
						}
					}
				}
			}
			// 当前请求移除处理完成,不需要进行视图渲染
			if (mavContainer.isRequestHandled()) {
				return null;
			}
			// 获取运行过程中的Modle数据
			ModelMap model = mavContainer.getModel();
			// 创建一个新的modelAndview,并包运行过程中的viewName,model数据,状态码给它
			ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
			// 如果运行过程中,mavContainer中的view不是String类型,也就是不是一个viewName
			if (!mavContainer.isViewReference()) {
				// 将view的类型改为View对象
				mav.setView((View) mavContainer.getView());
			}
			// 如果这个model为一个重定向的model
			if (model instanceof RedirectAttributes) {
				// 在Spring MVC中,下面代码是用来获取重定向时传递的Flash属性的代码,Flash属性是一种在重定向期间传递数据的机制
				// 当使用`RedirectAttributes`对象在控制器方法中执行重定向时,可以使用`addFlashAttribute`方法将属性添加到Flash范围中
				// 然后,重定向后的目标控制器中可以通过`getFlashAttributes`方法获取这些属性,并在视图中使用。
				// 这种机制特别适合需要在重定向期间传递数据但又不希望数据暴露在URL中的情况。
				Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
				HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
			return mav;
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值