spring mvc源码分析(一) 请求的执行过程

这是个人的一个学习的经历。。。。。。

spring mvc的版本是5.x的,sping mvc的入口是 DispatcherServlet 类 ,在之前的ssm项目中,我们是通过配置在web.xml中的servlet把请求的入口设置为DispatcherServlet,现在的版本官方不提倡编写web.xml,而是如下:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletCxt) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

原理是在spring-web项目下(spring-webmvc依赖于spring-web) 资源文件中 META-INF下services下的javax.servlet.ServletContainerInitializer文件中配置了org.springframework.web.SpringServletContainerInitializer类,

这个类在这个固定的路径文件下就意味着服务器比如tomcat启动的时候会去运行这个类,当然这个类继承了ServletContainerInitializer接口,固定会去运行startup方法。ServletContainerInitializer 是在javax.servlet中的,这个差不多就是一个规范一个标准,具体实现是在服务器例如tomcat中的。

而SpringServletContainerInitializer类配置了一行注解

@HandlesTypes(WebApplicationInitializer.class)

这个handlestypes的注解意思是会查找到继承了WebApplicationInitializer接口的类会被当成startup方法的参数传入,而SpringServletContainerInitializer的startup中会用反射调用实现了WebApplicationInitializer类的startup方法

if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					
     try {
					
	     initializers.add((WebApplicationInitializer);						 
         ReflectionUtils.accessibleConstructor(waiClass).newInstance());
		}
	catch (Throwable ex) {
			throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
			}
	}

回到最开始的官方代码,代码中注册了DispatcherServlet基本等同于xml中这样的一个效果。

  <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

 

请求到了这里之后,就可以来看DispatcherServlet的实现了,首先上类图

DispatcherServlet继承了servlet,而servlet类请求执行都是通过调用doGet和doPost方法,所以查看这两个方法的实现。具体在FrameworkServlet类中,两个方法的代码都是调用了processRequest(request, response)方法,在processRequest中先看这段代码

RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

先重点说明当前线程的RequestAttributes对象是在 RequestContextFilter中初始化的,主要之前一直疑惑为什么这里要重新将request和response对象放入本地线程变量中,后来发现会有这么个情况,那就是在RequestContextFilter和执行到DispatcherServlet这个mvc的sevlet中间我们可能对request或response对象进行封装修改操作,所以这里是一个同步最新的request和response对象的操作。

protected ServletRequestAttributes buildRequestAttributes(HttpServletRequest request,
			@Nullable HttpServletResponse response, @Nullable RequestAttributes previousAttributes) {

		if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
			return new ServletRequestAttributes(request, response);
		}
		else {
			return null;  // preserve the pre-bound RequestAttributes instance
		}
	}

接下来会运行doService(request, response)方法,而doService方法由子类DispatcherServlet继承执行,所以请求最后会执行doDispatch(request, response)方法。

doDispatch(HttpServletRequest request, HttpServletResponse response)

在方法中第一个重点是获取handler处理器

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

进入getHandler方法,是这样一段代码,循环一个已存在的HandlerMapping的List查找本次请求所需要的HandlerMapping,这个List以及getHandler方法都是在DispatcherServlet类中的,至于HandlerMapping列表什么时候存在的,怎么创建的?首先肯定是初始化的时候,具体情况先放一边。

(ps:此处是一个策略模式)

	if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}

点开getHandler方法,getHandler方法并不是由具体实现类去实现的,而是通过AbstractHandlerMapping这个抽象类,而在AbstractHandlerMapping的getHandler方法中,调用了getHandlerInternal方法,这个方法由子类去实现 (模板方法模式)。

先看RequestMappingHandlerMapping实现类,这个类继承自 AbstractHandlerMethodMapping,主要实现也是AbstractHandlerMethodMapping的getHandlerInternal方法,getHandlerInternal方法中调用了lookupHandlerMethod方法

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		request.setAttribute(LOOKUP_PATH, lookupPath);
		this.mappingRegistry.acquireReadLock();
		try {
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}

lookupHandlerMethod方法中从mappingRegistry这个map中查找对应的匹配结果,并最终得到 HandlerMethod,在mappingRegistry中,有多个map缓存,最终的HandlerMethod也是通过多次从这几个map中查找才获得,这其中的具体操作先放一边。

而在获取到HandlerMethod后,此时的method对象是一个最初的method,这个method将会生成最终的bean

return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

在createWithResolvedBean方法中,将会执行this.beanFactory.getBean(beanName),从spring容器中获取一个完整的bean,最终返回一个全新的HandlerMethod

	public HandlerMethod createWithResolvedBean() {
		Object handler = this.bean;
		if (this.bean instanceof String) {
			Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
			String beanName = (String) this.bean;
			handler = this.beanFactory.getBean(beanName);
		}
		return new HandlerMethod(this, handler);
	}

拿到handler之后,这时候handler从一个原始的java对象到spring bean到一个完整的spring mvc中的controller对象仅仅还是处于spring bean这个步骤,再回到AbstractHandlerMapping中的getHandler方法中

HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

在这个方法中,spring mvc的拦截器会被添加进来,最后会得到一个完整的HandlerExecutionChain 

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

再回到 DispatcherServlet类中,此时得到的HandlerExecutionChain对象就是一个完整的有拦截器并且被spring管理的一个handler对象。

拿到handler后,往下看,查找一个适配器

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		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");
	}

RequestMappingHandlerMapping对应的适配器是RequestMappingHandlerAdapter,在适配器中,通过supports去判断是否是传入的handle的适配器,这样的好处就是避免了大量的ifelse,而这里在拿到了对应的适配器后,再回到DispatcherServlet类中,先是执行了之前获取到的HandlerExecutionChain中的HandlerInterceptor拦截器链。

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

在这里,如果interceptor.preHandle方法返回的是false的话,会去触发triggerAfterCompletion也就是interceptor.afterCompletion方法。而在依次正常执行完interceptor拦截器之后,回到DispatcherServlet,就会去执行适配器的handle方法。

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这里再进到RequestMappingHandlerAdapter中,RequestMappingHandlerAdapter继承的是AbstractHandlerMethodAdapter,所以handle方法先调用AbstractHandlerMethodAdapter中的handle方法。

	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

而handleInternal方法被RequestMappingHandlerAdapter实现,handleInternal方法中最重要是这一行代码

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

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			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);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			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();
				LogFormatUtils.traceDebug(logger, traceOn -> {
					String formatted = LogFormatUtils.formatValue(result, !traceOn);
					return "Resume with async result [" + formatted + "]";
				});
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

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

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

先看getDataBinderFactory(handlerMethod),方法名称可以看出,这个方法是获取initBinder的

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
		Class<?> handlerType = handlerMethod.getBeanType();
		Set<Method> methods = this.initBinderCache.get(handlerType);
		if (methods == null) {
			methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
			this.initBinderCache.put(handlerType, methods);
		}
		List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
		// Global methods first
		this.initBinderAdviceCache.forEach((clazz, methodSet) -> {
			if (clazz.isApplicableToBeanType(handlerType)) {
				Object bean = clazz.resolveBean();
				for (Method method : methodSet) {
					initBinderMethods.add(createInitBinderMethod(bean, method));
				}
			}
		});
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			initBinderMethods.add(createInitBinderMethod(bean, method));
		}
		return createDataBinderFactory(initBinderMethods);
	}

首先,从initBinderCache中获取,如果当前是项目启动这个HandlerMethod的第一次请求,那么initBinderCache这个map中肯定是空的,就会查找注解了InitBinder的方法并放入缓存中,再来请求的话就会直接跳过,从缓存中取。然后再从initBinderAdviceCache中获取,initBinderAdviceCache中存放的是注解了@ControllerAdvice中的类,不过initBinderMethods添加的顺序是先initBinderAdviceCache,然后再是initBinderCache,最后获取WebDataBinderFactory返回。

回到invokeHandlerMethod方法,接下来就是getModelFactory(handlerMethod, binderFactory)方法

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
		SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
		Class<?> handlerType = handlerMethod.getBeanType();
		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<>();
		// Global methods first
		this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
			if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
				Object bean = controllerAdviceBean.resolveBean();
				for (Method method : methodSet) {
					attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
				}
			}
		});
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
		}
		return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
	}

getModelFactory中的做法和之前的getDataBinderFactory方法类似,modelAttributeCache中存放的是对应的handlerMethod中存在@ModelAttribute(不能有@RequestMapping)注解的方法,而modelAttributeAdviceCache存放的就是有@ControllerAdvice注解的类中具有@ModelAttribute注解(不能有@RequestMapping)的方法,最后创建一个ModelFactory并返回

然后再回到invokeHandlerMethod方法,接下来创建一个createInvocableHandlerMethod,设置argumentResolvers,returnValueHandlers,binderFactory,parameterNameDiscoverer,总之就是初始化了一个ServletInvocableHandlerMethod,ServletInvocableHandlerMethod是HandlerMethod类的一个扩展,具备了参数解析,返回值解析等功能, 然后初始化一个ModelAndViewContainer

modelFactory.initModel(webRequest, mavContainer, invocableMethod);

initModel方法中会执行注解了@ModelAttribute的方法的流程,不怎么用模板,因此带过。

跳过异步的代码,往下看,

invocableMethod.invokeAndHandle(webRequest, mavContainer)

 进入invokeAndHandle方法中的第一句代码

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
		return doInvoke(args);
	}

invokeForRequest方法中,getMethodArgumentValues是获取当前方法所需的参数,细节先放一边,往下看doInvoke方法

return getBridgedMethod().invoke(getBean(), args);

这一行代码是目标方法最终执行的地方,getBridgedMethod()是父类HandlerMethod的方法,其最终构建过程在之前说的AbstractHandlerMethodMapping中createWithResolvedBean方法中。此时获取的是当前的Controller对象,也就是当前请求的类的原始对象,而getBean()方法获取到的就是spring容器中取出的Bean,这个Bean是包含了spring中各种aop的spring bean。最终该方法执行得到结果返回。回到invokeAndHandle方法中

	try {
			this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}

这里selectHandler方法明显是获取对应的Handler方法,方式和之前获取对应的适配器类似

	private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
		boolean isAsyncValue = isAsyncReturnValue(value, returnType);
		for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
			if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
				continue;
			}
			if (handler.supportsReturnType(returnType)) {
				return handler;
			}
		}
		return null;
	}

所以这里对应不同的类型,有不同的returnHandler处理器,这里看RequestResponseBodyMethodProcessor处理器

	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

重点是writeWithMessageConverters方法

try {
			message = new EmptyBodyCheckingHttpInputMessage(inputMessage);

			for (HttpMessageConverter<?> converter : this.messageConverters) {
				Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
				GenericHttpMessageConverter<?> genericConverter =
						(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
				if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
						(targetClass != null && converter.canRead(targetClass, contentType))) {
					if (message.hasBody()) {
						HttpInputMessage msgToUse =
								getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
						body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
								((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
						body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
					}
					else {
						body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
					}
					break;
				}
			}
		}

方法中选择了对应的HttpMessageConverter,并且调用了getAdvice()的方法,这个Advice就是实现了ResponseBodyAdvice的类,最后write输出。

if (body != null) {
	Object theBody = body;
	LogFormatUtils.traceDebug(logger, traceOn ->
			"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
	addContentDispositionHeader(inputMessage, outputMessage);
	if (genericConverter != null) {
		genericConverter.write(body, targetType, selectedMediaType, outputMessage);
	}
	else {
		((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
	}

最后再回到RequestMappingHandlerAdapter,接下来获取ModelAndView,当前主要说rest请求,所以这里跳过。

return getModelAndView(mavContainer, modelFactory, webRequest);

接着就回到了DispatchServlet中

mappedHandler.applyPostHandle(processedRequest, response, mv);

这里会去调用拦截器的postHandle方法,再往下

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

在这个方法中,回去调用拦截器的afterCompletion方法。

到此为止,spring mvc的一个请求的执行周期就已经基本结束了。以上说的只是一个大概的过程,具体的细节放到后续的博客里面

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值