Springmvc中的dispatcherServlet执行过程一探究竟

背景	:
前端请求中的参数一直映射不到自定义的Bean中。于是便想自己看下这个转换的过程。

1.调研

当然已经有很多大佬进行过自己的分析。好文章一大摞,但是找到适合自己的,自己看的有意思的却很费劲。我这里先分享几个:
1)Spring序列化与反序列化设计探究
2)SpringMVC对象绑定时自定义名称对应关系
3)Tomcat各组件分析

2.实现

  1. 具体代码实现我抄了下第二篇文章。在最后注入argument-resolvers时有了一点自己的体会,这个内容之后分析下。
  2. 我觉得我们可以先看下第三篇文章对Tomcat的结构有一个大概的印象。
  3. 开始研究dispatchservlet中执行代码

3.dispatchservlet 代码执行逻辑分析

  1. doDispatch方法
try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				//根据request请求路径找到对应的requestMapping方法
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				//做一些handle表象之外的额外事情
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
  1. handlerAdapter 的handle方法
    在这里插入图片描述
    看adapter的实现类,我们以RequestMappingHandlerAdapter为例,进入到handle方法中:
@Override
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}
	
	@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
			……
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
			……
		return mav;
	}

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

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			……

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			……
			
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

//顺着方法一直进入到
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);
			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.isDebugEnabled()) {
						logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
					}
					throw ex;
				}
			}
			if (args[i] == null) {
				throw new IllegalStateException("Could not resolve method parameter at index " +
						parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
						": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
			}
		}
		return args;
	}

终于看到了和我们上一步加的resolver相关的代码了。接着看会儿源码:

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

		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
		if (resolver == null) {
			throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
		}
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}

//接口
public interface HandlerMethodArgumentResolver {

	boolean supportsParameter(MethodParameter parameter);

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

}

我们首先看下都有哪些实现类吧:
在这里插入图片描述
是不是感觉一些实现类很眼熟。是的,就是我们经常使用的一些注解。我们先看下这些实现类的继承结构吧:
在这里插入图片描述

我们找几个实现类看下,觉得每个实现类都是对注解所达的含义进行相关值的解析。那么我们不使用任何注解,是如何进行解析操作的呢,那么就到了我们一开始的问题了:

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

		Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :
				createAttribute(name, parameter, binderFactory, webRequest));

		WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
		if (binder.getTarget() != null) {
			if (!mavContainer.isBindingDisabled(name)) {
				bindRequestParameters(binder, webRequest);
			}
			……
		}

		// Add resolved attribute and BindingResult at the end of the model
		……

		return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
	}

这里我们看的主要方法是bindRequestParameters,光看名字就觉的自己懂了。这个方法咱们自定义的resolver方法同样也实现了这个方法。我们就接着跟代码:

//由对应的dataBinder类调用bind方法:
camelBinder.bind(request.getNativeRequest(ServletRequest.class));

public void bind(ServletRequest request) {
		MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
		MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
		if (multipartRequest != null) {
			bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
		}
		addBindValues(mpvs, request);
		doBind(mpvs);
	}

到这里已经可以叫好了,我们自己的dataBinder重写了这个addBindValues方法。所以咱们自定义实体类的映射过程就大概如此。咱们再回到父类的resolveArgument方法中,方法最后还执行了convertIfNecessary方法,这个过程是进行了一些数据转换,如时间转换等和验证逻辑。

4.回顾

Q:为什么一开始我自定义的resolver没有注册成功呢,在argumentResolvers列表中没有看到呢?

@Configuration
public class WebContextConfiguration extends WebMvcConfigurationSupport {

	@Override
	protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
		super.addArgumentResolvers(argumentResolvers);
		argumentResolvers.add(processor());
	}

	}
}

A: 因为我这里是spring+springmvc项目,controller的实例化是放在springmvc容器中的。 这里涉及到父子容器的问题,也经常遇到事务相关问题。最后解决也是由配置:

	<!-- 使用Annotation自动注册Bean,只扫描@Controller -->
	<context:component-scan base-package="com.zhzg.appcore"
							use-default-filters="false"><!-- base-package 如果多个,用“,”分隔 -->
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>


	<!-- 默认的注解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
	<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
		<mvc:argument-resolvers>
			<bean class="com.zhzg.appcore.common.servlet.SnakeToCamelModelAttributeMethodProcessor">
				<constructor-arg name="annotationNotRequired" value="true"/>
			</bean>
		</mvc:argument-resolvers>
    </mvc:annotation-driven>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值