SpringMVC工作原理(二)

上一篇中,一步步走到了HandleAdapter的处理,看到了关键方法RequestMappingHandleAdapter的invokeHandleMethod方法,这一篇接着往下看~

RequestMappingHandleAdapter#invokeHandleMethod

这个方法比较复杂,简单讲就是根据request中的参数,映射到对应@RequestMapping注解的方法的参数中,然后执行业务代码逻辑,最后封装ModelAndView对象返回。

private ModelAndView invokeHandleMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        // 包装成ServletWebRequest 对象
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
        // 创建WebDataBinder工厂
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 获取Model工厂
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        // 包装HandleMethod
		ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
        // 创建ModelAndViewContainer
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        // 将FlashMap中的参数添加到mavContainer 中
        // 一般是用于获取RedirectAttributes.addFlashAttribute('key','value')中的参数
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 初始化Model对象
		modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        // 异步相关的处理
		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		final 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 + "]");
			}
			requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
		}

        // 执行@RequestMapping注解的业务方法
		requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

		return getModelAndView(mavContainer, modelFactory, webRequest);
	}

getDataBinderFactory

获取处理器方法对应的WebDataBinder组件,其实就是将@InitBinder注解的方法保存到WebDataBinderFactory,因为这些方法要对request中的一些参数进行处理。

    // 方法过滤器,过滤出带有@InitBinder的方法
	public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() {

		@Override
		public boolean matches(Method method) {
			return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;
		}
	};

	private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
        // 获取该Controller的Class
		Class<?> handlerType = handlerMethod.getBeanType();
        // 从缓存中找这个Controller含有的@InitBinder注解的方法
		Set<Method> methods = this.initBinderCache.get(handlerType);
		if (methods == null) {
            // 缓存中没有则去Controller中查找
			methods = HandlerMethodSelector.selectMethods(handlerType, INIT_BINDER_METHODS);
            // 找到后添加到缓存
			this.initBinderCache.put(handlerType, methods);
		}
		List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
		// Global methods first
        // 遍历在使用了@ControlerAdvice的类中添加了@InitBinder的方法
        // 这些方法属于全局的InitBinder方法,不单独对某一个Controller生效,所以要放在List的前面
		for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache .entrySet()) {
			if (entry.getKey().isApplicableToBeanType(handlerType)) {
				Object bean = entry.getKey().resolveBean();
				for (Method method : entry.getValue()) {
					initBinderMethods.add(createInitBinderMethod(bean, method));
				}
			}
		}
        // 将当前Controller中使用了@InitBinder方法添加到集合中
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			initBinderMethods.add(createInitBinderMethod(bean, method));
		}
        // 创建WebDataBinderFactory对象
		return createDataBinderFactory(initBinderMethods);
	}

	protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
			throws Exception {

		return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
	}

getModelFactory

和getDataBindFactory方法类似,这个方法就是将使用了@ModelAttribute注解的方法保存起到ModelFactory。

    // 方法过滤器,过滤出使用了@ModelAttribute注解但未使用@RequestMapping注解的方法
	public static final MethodFilter MODEL_ATTRIBUTE_METHODS = new MethodFilter() {

		@Override
		public boolean matches(Method method) {
			return ((AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) &&
					(AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null));
		}
	};

	private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
        // 用于处理@SessionAttributes
		SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
		Class<?> handlerType = handlerMethod.getBeanType();
        // 从缓存中找该Controller中使用了@ModelAttribute的方法
		Set<Method> methods = this.modelAttributeCache.get(handlerType);
		if (methods == null) {
            // 没有则去该Controller中找
			methods = HandlerMethodSelector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
            // 找到后添加到缓存
			this.modelAttributeCache.put(handlerType, methods);
		}
		List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
		// Global methods first
        // 遍历在使用了@ControlerAdvice的类中添加了@ModelAttribute的方法
        // 这些方法属于全局的@ModelAttribute方法,不单独对某一个Controller生效,所以要放在List的前面
		for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
			if (entry.getKey().isApplicableToBeanType(handlerType)) {
				Object bean = entry.getKey().resolveBean();
				for (Method method : entry.getValue()) {
					attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
				}
			}
		}
        // 将当前Controller中使用了@ModelAttribute方法添加到集合中
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
		}
        // 创建ModelFactory对象
		return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
	}

	public ModelFactory(List<InvocableHandlerMethod> attributeMethods,
						WebDataBinderFactory binderFactory,
						SessionAttributesHandler sessionAttributesHandler) {
		this.attributeMethods = (attributeMethods != null) ? attributeMethods : new ArrayList<InvocableHandlerMethod>();
		this.binderFactory = binderFactory;
		this.sessionAttributesHandler = sessionAttributesHandler;
	}

createRequestMappingMethod

将HandleMethod进行一次包装

	private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

	private ServletInvocableHandlerMethod createRequestMappingMethod(
			HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {

		ServletInvocableHandlerMethod requestMethod;
		requestMethod = new ServletInvocableHandlerMethod(handlerMethod);
		requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		requestMethod.setDataBinderFactory(binderFactory);
		requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		return requestMethod;
	}

	

其中的一些属性,都是在当前类即RequestMappingHandlerAdapter初始化的时候设置进去的,通过实现InitializingBean接口的afterPropertiesSet方法。

    @Override
	public void afterPropertiesSet() {
		if (this.argumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		if (this.initBinderArgumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		if (this.returnValueHandlers == null) {
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
		initControllerAdviceCache();
	}

/**
	 * Return the list of argument resolvers to use including built-in resolvers
	 * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
	 */
	private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ServletModelAttributeMethodProcessor(false));
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new RequestHeaderMapMethodArgumentResolver());
		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
		resolvers.add(new RedirectAttributesMethodArgumentResolver());
		resolvers.add(new ModelMethodProcessor());
		resolvers.add(new MapMethodProcessor());
		resolvers.add(new ErrorsMethodArgumentResolver());
		resolvers.add(new SessionStatusMethodArgumentResolver());
		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		resolvers.add(new ServletModelAttributeMethodProcessor(true));

		return resolvers;
	}

	/**
	 * Return the list of argument resolvers to use for {@code @InitBinder}
	 * methods including built-in and custom resolvers.
	 */
	private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());

		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));

		return resolvers;
	}

	/**
	 * Return the list of return value handlers to use including built-in and
	 * custom handlers provided via {@link #setReturnValueHandlers}.
	 */
	private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
		List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

		// Single-purpose return value types
		handlers.add(new ModelAndViewMethodReturnValueHandler());
		handlers.add(new ModelMethodProcessor());
		handlers.add(new ViewMethodReturnValueHandler());
		handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
		handlers.add(new HttpHeadersReturnValueHandler());
		handlers.add(new CallableMethodReturnValueHandler());
		handlers.add(new DeferredResultMethodReturnValueHandler());
		handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

		// Annotation-based return value types
		handlers.add(new ModelAttributeMethodProcessor(false));
		handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));

		// Multi-purpose return value types
		handlers.add(new ViewNameMethodReturnValueHandler());
		handlers.add(new MapMethodProcessor());

		// Custom return value types
		if (getCustomReturnValueHandlers() != null) {
			handlers.addAll(getCustomReturnValueHandlers());
		}

		// Catch-all
		if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
			handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
		}
		else {
			handlers.add(new ModelAttributeMethodProcessor(true));
		}

		return handlers;
	}

	private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache =
			new LinkedHashMap<ControllerAdviceBean, Set<Method>>();

	private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache =
			new LinkedHashMap<ControllerAdviceBean, Set<Method>>();

    // 找到全局的ControllerAdvice中的存在的@ModelAttribute和@InitBinder方法
    // 设置到属性中作为缓存使用
	private void initControllerAdviceCache() {
		if (getApplicationContext() == null) {
			return;
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for controller advice: " + getApplicationContext());
		}

		List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
		Collections.sort(beans, new OrderComparator());

		for (ControllerAdviceBean bean : beans) {
			Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
			if (!attrMethods.isEmpty()) {
				this.modelAttributeAdviceCache.put(bean, attrMethods);
				logger.info("Detected @ModelAttribute methods in " + bean);
			}
			Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
			if (!binderMethods.isEmpty()) {
				this.initBinderAdviceCache.put(bean, binderMethods);
				logger.info("Detected @InitBinder methods in " + bean);
			}
		}
	} 

ModelFactory#initModel

	public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
			throws Exception {
        // 获取使用了@SessionAttributes后保存在session的参数
		Map<String, ?> attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request);
        // 合并到mavContainer
        // 当前mavContainer中不存在则设置, 存在则略过
		mavContainer.mergeAttributes(attributesInSession);
        // 调用使用了@ModelAttribute的方法
		invokeModelAttributeMethods(request, mavContainer);
        // 遍历使用了@ModelAttribute的参数名在session中存在的参数
		for (String name : findSessionAttributeArguments(handlerMethod)) {
            // Model中不存在则在session里找到并设置到Model
			if (!mavContainer.containsAttribute(name)) {
				Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
				if (value == null) {
					throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
				}
				mavContainer.addAttribute(name, value);
			}
		}
	}

ModelFactory#invokeModelAttributeMethod

执行@ModelAttribute方法

	private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer)
			throws Exception {

        // 遍历需要执行的ModelAttribute方法
		for (InvocableHandlerMethod attrMethod : this.attributeMethods) {
            // 获取注解的value属性
			String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
            // 如果Model中已经有了这个属性则跳过
			if (mavContainer.containsAttribute(modelName)) {
				continue;
			}
            // 执行该方法得到返回值
			Object returnValue = attrMethod.invokeForRequest(request, mavContainer);
            // 返回值不为Void
			if (!attrMethod.isVoid()){
                // 获取返回的值对应的属性名
                // 取@ModelAttribute的value属性, 没有则进行一系列的处理得到一个
				String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
                // Model中不存在则设置到Model中
				if (!mavContainer.containsAttribute(returnValueName)) {
					mavContainer.addAttribute(returnValueName, returnValue);
				}
			}
		}
	}

通过invokeForRequest方法处理参数后调用具体ModelAttribute方法

	public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        // 获取方法参数的值
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			StringBuilder sb = new StringBuilder("Invoking [");
			sb.append(getBeanType().getSimpleName()).append(".");
			sb.append(getMethod().getName()).append("] method with arguments ");
			sb.append(Arrays.asList(args));
			logger.trace(sb.toString());
		}
        // 拿到参数后, 反射调用具体方法逻辑,获取返回值
		Object returnValue = invoke(args);
		if (logger.isTraceEnabled()) {
			logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
		}
		return returnValue;
	}

    private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        // 获取方法参数对象数组
		MethodParameter[] parameters = getMethodParameters();
        // 保存每个参数的值
		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
            // 解析通过providedArgs提供的预留参数,当providedArgs中有与当前遍历的参数类型匹配的参数值时直接使用
            // 处理器方法调用时,provided为空,但在异常解析方法与@InitBinder方法调用时有额外提供的参数
			args[i] = resolveProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
            // 根据前面初始化的参数解析器判断该参数是否可以解析
			if (this.argumentResolvers.supportsParameter(parameter)) {
				try {
                    // 解析参数,解析过程出错则抛出异常
					args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
					continue;
				} catch (Exception ex) {
					if (logger.isTraceEnabled()) {
						logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
					}
					throw ex;
				}
			}
            // 参数无法解析则抛出异常
			if (args[i] == null) {
				String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
				throw new IllegalStateException(msg);
			}
		}
		return args;
	}

	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 找到该参数对应的参数处理器
		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
		Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
        //  使用该处理器解析参数
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}

	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        // 从缓存中查找该参数是否有对应的处理器
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
            // 没有则遍历参数处理器找
			for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
				if (logger.isTraceEnabled()) {
					logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
							parameter.getGenericParameterType() + "]");
				}
                // 找到支持该参数解析的处理器后设置到缓存并返回
				if (methodArgumentResolver.supportsParameter(parameter)) {
					result = methodArgumentResolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

HandlerMethodArgumentResolver#resolveArgument

参数处理器, 常用的实现有 RequestParamMethodArgumentResolver 和 PathVariableArgumentResolver。见名知意,就是在我们使用 @RequetParam 和 @PathVariable 注解的时候会匹配上这两个参数处理器,他们都有共同的父类AbstractNamedValueMethodArgumentResolver,一般普通的参数都会调用这个类。

public class AbstractNamedValueMethodArgumentResolver {
    public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        // 从request中找到与之对应的参数,值作为arg变量返回
		Class<?> paramType = parameter.getParameterType();
		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);

		Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
		if (arg == null) {
			if (namedValueInfo.defaultValue != null) {
				arg = resolveDefaultValue(namedValueInfo.defaultValue);
			}
			else if (namedValueInfo.required) {
				handleMissingValue(namedValueInfo.name, parameter);
			}
			arg = handleNullValue(namedValueInfo.name, arg, paramType);
		}
		else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
			arg = resolveDefaultValue(namedValueInfo.defaultValue);
		}

        // 处理@InitBinder
		if (binderFactory != null) {
			WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
			arg = binder.convertIfNecessary(arg, paramType, parameter);
		}
        // 留给子类实现,在参数处理完成之后再做一些特定的处理
		handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

		return arg;
	}
}

处理@InitBinder

public class DefaultDataBinderFactory {

	public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
			throws Exception {
		WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
		if (this.initializer != null) {
			this.initializer.initBinder(dataBinder, webRequest);
		}
        // 初始化initBinder
		initBinder(dataBinder, webRequest);
		return dataBinder;
	}
}

public class InitBinderDataBinderFactory {
    
	public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
        // 在之前创建WebDataBinderFacotry时将@InitBinder的方法都设置到了binderMethods中
		for (InvocableHandlerMethod binderMethod : this.binderMethods) {
			if (isBinderMethodApplicable(binderMethod, binder)) {
                // 调用@InitBinder方法
				Object returnValue = binderMethod.invokeForRequest(request, null, binder);
                // 在这里可以看到@InitBinder方法返回值必须是void, idea编辑器在写的时候就会提示
				if (returnValue != null) {
					throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);
				}
			}
		}
	}

}

HandlerMethod#invokeAndHandle

public final void invokeAndHandle(ServletWebRequest webRequest,
			ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        // 参数解析,调用业务代码逻辑,得到返回值
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        // 设置响应状态码
		setResponseStatus(webRequest);
        // 返回值为空
		if (returnValue == null) {
            // 请求内容未修改 || 响应状态码不为空 || 标记了请求已经处理
			if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                // 请求已处理,返回
				mavContainer.setRequestHandled(true);
				return;
			}
		}
        // 有返回值 且 有响应的原因,则标记请求已处理,返回
		else if (StringUtils.hasText(this.responseReason)) {
			mavContainer.setRequestHandled(true);
			return;
		}
        // 设置请求未处理
		mavContainer.setRequestHandled(false);

		try {
            // 返回值处理器,处理返回值
			this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}

HandlerMethodReturnValueHandler#handleReturnValue

返回值处理器,用于处理业务代码的返回值,一般使用了@ResponseBody的会适配到RequestResponseBodyMethodProcessor来处理,未使用的一般是返回一个String当做视图名称,会适配到ViewNameMethodReturnValueHandler来处理。

public class RequestResponseBodyMethodProcessor {

    // 适配到该方法或该类使用了@ResponseBody
	public boolean supportsReturnType(MethodParameter returnType) {
		return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null ||
				returnType.getMethodAnnotation(ResponseBody.class) != null);
	}

    // 处理返回值
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException {
        // 设置请求已处理
		mavContainer.setRequestHandled(true);
		if (returnValue != null) {
            // 返回值不为空则调用消息转换器转换后写到response
			writeWithMessageConverters(returnValue, returnType, webRequest);
		}
	}

    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

		Object argument = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
		String name = Conventions.getVariableNameForParameter(parameter);
		WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name);
		if (argument != null) {
			validate(binder, parameter);
		}
		mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
		return argument;
	}

	private void validate(WebDataBinder binder, MethodParameter parameter) throws Exception {
		Annotation[] annotations = parameter.getParameterAnnotations();
		for (Annotation ann : annotations) {
			if (ann.annotationType().getSimpleName().startsWith("Valid")) {
				Object hints = AnnotationUtils.getValue(ann);
				binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
				BindingResult bindingResult = binder.getBindingResult();
				if (bindingResult.hasErrors()) {
					if (isBindExceptionRequired(binder, parameter)) {
						throw new MethodArgumentNotValidException(parameter, bindingResult);
					}
				}
				break;
			}
		}
	}

}

public class ViewNameMethodReturnValueHandler {

    // 适配到返回值是void或String
	public boolean supportsReturnType(MethodParameter returnType) {
		Class<?> paramType = returnType.getParameterType();
		return (void.class.equals(paramType) || String.class.equals(paramType));
	}

    // 处理返回值
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // 返回值为null则不处理
		if (returnValue == null) {
			return;
		}
        // 返回值是String,则设置为视图名称
		else if (returnValue instanceof String) {
			String viewName = (String) returnValue;
			mavContainer.setViewName(viewName);
            // 是重定向则设置重定向标志
			if (isRedirectViewName(viewName)) {
				mavContainer.setRedirectModelScenario(true);
			}
		}
		else {
			// should not happen
			throw new UnsupportedOperationException("Unexpected return type: " +
					returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
		}
	}
    
    // 判断是否是重定向
	protected boolean isRedirectViewName(String viewName) {
		return viewName.startsWith("redirect:");
	}
}

RequetstMappingHandlerAdapter#getModelAndView

	private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
        // 更新Model
		modelFactory.updateModel(webRequest, mavContainer);
        // 判断请求是否已处理
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		ModelMap model = mavContainer.getModel();
        // 创建ModelAndView对象准备返回
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
        // 判断是否是视图引用, 即字符串视图名,如果不是则直接强转为View对象
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
        // 判断是否是重定向,是则把属性值等都设置到flashMap
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
		}
		return mav;
	}

DispatchServlet#applyDefaultViewName

    // 如果ModelAndView不为空,且ModelAndView还没有值(@ResponseBody ModelAndView为null)
    // 那么就根据请求来翻译出一个默认的视图名
	private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
		if (mv != null && !mv.hasView()) {
			mv.setViewName(getDefaultViewName(request));
		}
	}

DispatchServlet#applyPostHandle

之前说到在请求处理之前会调用前置拦截器,这里请求处理完了就开始调用后置拦截器。具体过程和调用前置拦截器一样,不过这里的顺序得反过来,因为最先调用的前置拦截方法要最后调用其后置拦截方法。

public class HandlerExecutionChain {

	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (getInterceptors() != null) {
			for (int i = 0; i < getInterceptors().length; i++) {
				HandlerInterceptor interceptor = getInterceptors()[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
		if (getInterceptors() == null) {
			return;
		}
		for (int i = getInterceptors().length - 1; i >= 0; i--) {
			HandlerInterceptor interceptor = getInterceptors()[i];
			interceptor.postHandle(request, response, this.handler, mv);
		}
	}

	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
			throws Exception {

		if (getInterceptors() == null) {
			return;
		}
        // interceptorIndex 是
		for (int i = this.interceptorIndex; i >= 0; i--) {
			HandlerInterceptor interceptor = getInterceptors()[i];
			try {
				interceptor.afterCompletion(request, response, this.handler, ex);
			}
			catch (Throwable ex2) {
				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
			}
		}
	}
}

DispatchServlet#processDispatchResult

该方法先判断在之前的处理过程中是否出现了异常,出现了则调用异常处理器来处理。之后判断是否需要渲染视图,完成之后再根据传入的HandlerExecutionChain来判断是否执行请求完成之后的拦截方法。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

		boolean errorView = false;
        // 在之前的处理中是否出现了异常
		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                // 异常处理器来处理
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
        // 无异常则判断是否需要渲染视图
		if (mv != null && !mv.wasCleared()) {
            // 渲染视图
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
						"': assuming HandlerAdapter completed request handling");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

ViewResolver#resolveException

异常处理器作为SpringMVC的九大组件之一,在WEB上下文初始化的时候设置,通过调用refresh方法最后执行了DispatcherServlet的initStrategies方法。

通常,项目中会使用全局异常处理,即用了@ExceptionHandler注解的时候,会适配到AnnotationMethodHandlerExceptionResolver ;

另外也可以配置异常和对应页面的一些映射,比如出现了异常的老祖宗Throwable就跳转到自定义的500页面,这可以通过配置SimpleMappingExceptionResolver到上下文来进行异常处理;

也可以什么都不配置,使用默认的DefaultHandlerExceptionResolver来处理;

public class DispatcherServlet {
    
    protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception ex) throws Exception {

		// Check registered HandlerExceptionResolvers...
		ModelAndView exMv = null;
        // 遍历异常处理器找到一个适配上的进行处理
		for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
			exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
			if (exMv != null) {
				break;
			}
		}
		if (exMv != null) {
			if (exMv.isEmpty()) {
				return null;
			}
			// We might still need view name translation for a plain error model...
			if (!exMv.hasView()) {
				exMv.setViewName(getDefaultViewName(request));
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
			}
			WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
			return exMv;
		}

		throw ex;
	}

}

// DefaultHandlerExceptionResolver 的父类
public class AbstractHandlerExceptionResolver {
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception ex) {
        // 判断是否匹配
		if (shouldApplyTo(request, handler)) {
			// Log exception, both at debug log level and at warn level, if desired.
			if (logger.isDebugEnabled()) {
				logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
			}
			logException(ex, request);
			prepareResponse(ex, response);
            // 处理异常逻辑, 交给子类实现
			return doResolveException(request, response, handler, ex);
		}
		else {
			return null;
		}
	}
}

public class DefaultHandlerExceptionResolver {

    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception ex) {
        // 根据异常类型进行不同的处理
		try {
			if (ex instanceof NoSuchRequestHandlingMethodException) {
				return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) ex, request, response,
						handler);
			}
			else if (ex instanceof HttpRequestMethodNotSupportedException) {
				return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
						response, handler);
			}
			else if (ex instanceof HttpMediaTypeNotSupportedException) {
				return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
						handler);
			}
			else if (ex instanceof HttpMediaTypeNotAcceptableException) {
				return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, request, response,
						handler);
			}
			else if (ex instanceof MissingServletRequestParameterException) {
				return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, request,
						response, handler);
			}
			else if (ex instanceof ServletRequestBindingException) {
				return handleServletRequestBindingException((ServletRequestBindingException) ex, request, response,
						handler);
			}
			else if (ex instanceof ConversionNotSupportedException) {
				return handleConversionNotSupported((ConversionNotSupportedException) ex, request, response, handler);
			}
			else if (ex instanceof TypeMismatchException) {
				return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
			}
			else if (ex instanceof HttpMessageNotReadableException) {
				return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, request, response, handler);
			}
			else if (ex instanceof HttpMessageNotWritableException) {
				return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
			}
			else if (ex instanceof MethodArgumentNotValidException) {
				return handleMethodArgumentNotValidException((MethodArgumentNotValidException) ex, request, response, handler);
			}
			else if (ex instanceof MissingServletRequestPartException) {
				return handleMissingServletRequestPartException((MissingServletRequestPartException) ex, request, response, handler);
			}
			else if (ex instanceof BindException) {
				return handleBindException((BindException) ex, request, response, handler);
			}
			else if (ex instanceof NoHandlerFoundException) {
				return handleNoHandlerFoundException((NoHandlerFoundException) ex, request, response, handler);
			}
		}
		catch (Exception handlerException) {
			logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
		}
		return null;
	}
    
  
	protected ModelAndView handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException ex,
			HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {

		pageNotFoundLogger.warn(ex.getMessage());
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
		return new ModelAndView();
	}
}

DispatcherServlet#render

渲染视图

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
        // 国际化组件
		Locale locale = this.localeResolver.resolveLocale(request);
		response.setLocale(locale);

		View view;
        // 是否是引用视图,即只有视图名String,没有对应的视图对象View
		if (mv.isReference()) {
			// We need to resolve the view name.
            // 根据视图名找到对应视图封装成View对象返回
			view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
            // 非引用视图则直接拿视图对象
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		try {
            // 调用渲染方法
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}

	protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
			HttpServletRequest request) throws Exception {
        // 遍历视图解析器,找到匹配的进行视图解析
		for (ViewResolver viewResolver : this.viewResolvers) {
			View view = viewResolver.resolveViewName(viewName, locale);
			if (view != null) {
				return view;
			}
		}
		return null;
	}

需要解析什么样的视图,就可以定义什么样的解析器;比如默认的视图解析器是解析JSP的InternalSourceViewResolver, 另外还有解析thymeleaf的ThymeleafViewResolver解析器等等。这里以InternalSourceViewResolver举例。

// InternalSourceViewResolver 父类
public class AbstractCachingViewResolver {
        // 有缓存则从缓存获取
        // 没有就调用createView方法创建View对象
    	public View resolveViewName(String viewName, Locale locale) throws Exception {
		if (!isCache()) {
			return createView(viewName, locale);
		}
		else {
			Object cacheKey = getCacheKey(viewName, locale);
			View view = this.viewAccessCache.get(cacheKey);
			if (view == null) {
				synchronized (this.viewCreationCache) {
					view = this.viewCreationCache.get(cacheKey);
					if (view == null) {
						// Ask the subclass to create the View object.
						view = createView(viewName, locale);
						if (view == null && this.cacheUnresolved) {
							view = UNRESOLVED_VIEW;
						}
						if (view != null) {
							this.viewAccessCache.put(cacheKey, view);
							this.viewCreationCache.put(cacheKey, view);
							if (logger.isTraceEnabled()) {
								logger.trace("Cached view [" + cacheKey + "]");
							}
						}
					}
				}
			}
			return (view != UNRESOLVED_VIEW ? view : null);
		}
	}

    // 调用loadView, 交给子类实现
	protected View createView(String viewName, Locale locale) throws Exception {
		return loadView(viewName, locale);
	}

}

// InternalSourceViewResolver 父类 
public class UrlBasedViewResolver {

	private static final boolean jstlPresent = ClassUtils.isPresent(
			"javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader());

    // 设置viewClass为InternalResourceView或JstlView
    // 如果有JSTL的api, 那么就是JstlView
    // JstlView是InternalResourceView的子类
	public InternalResourceViewResolver() {
		Class<?> viewClass = requiredViewClass();
		if (viewClass.equals(InternalResourceView.class) && jstlPresent) {
			viewClass = JstlView.class;
		}
		setViewClass(viewClass);
	}

    @Override
	protected View loadView(String viewName, Locale locale) throws Exception {
		AbstractUrlBasedView view = buildView(viewName);
		View result = applyLifecycleMethods(viewName, view);
		return (view.checkResource(locale) ? result : null);
	}

	protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
		view.setUrl(getPrefix() + viewName + getSuffix());

		String contentType = getContentType();
		if (contentType != null) {
			view.setContentType(contentType);
		}

		view.setRequestContextAttribute(getRequestContextAttribute());
		view.setAttributesMap(getAttributesMap());

		Boolean exposePathVariables = getExposePathVariables();
		if (exposePathVariables != null) {
			view.setExposePathVariables(exposePathVariables);
		}

		return view;
	}

	private View applyLifecycleMethods(String viewName, AbstractView view) {
		return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);
	}
}

public class InternalSourceViewResolver{

	protected AbstractUrlBasedView buildView(String viewName) throws Exception {

        // 调用父类UrlBasedViewResolver的buildView方法
		InternalResourceView view = (InternalResourceView) super.buildView(viewName);
		if (this.alwaysInclude != null) {
			view.setAlwaysInclude(this.alwaysInclude);
		}
		if (this.exposeContextBeansAsAttributes != null) {
			view.setExposeContextBeansAsAttributes(this.exposeContextBeansAsAttributes);
		}
		if (this.exposedContextBeanNames != null) {
			view.setExposedContextBeanNames(this.exposedContextBeanNames);
		}
		view.setPreventDispatchLoop(true);
		return view;
	}
}

虽然有些绕,但还是可以根据InternalSourceViewResolver的viewClass属性实例化了一个View对象,根据prefix和suffix,以及视图名组成了一个完整的url设置到View对象中,以及一些其他属性。拿到View对象之后执行render方法开始渲染视图。

至此,SpringMVC的工作流程及原理也就了解的差不多了,有些地方写的比较粗糙一点,以后有机会了再细化吧。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值