springmvc原理解析

springmvc执行过程分析

源码分析

前端解析器的UML图

  • 因为是对前端请求的URL进行处理,我们只需要看Servlet的继承类就可以了

初始化(主要工作:上下文初始化,和解析器初始化)

  • FrameworkServlet

    • 初始化Servlet的上下文, 调用子类的onFresh方法 进行初始化;

protected final void initServletBean() throws ServletException {
       //。。。。。。。
	long startTime = System.currentTimeMillis();

	try {
		this.webApplicationContext = initWebApplicationContext();
		initFrameworkServlet();
	}catch (ServletException | RuntimeException ex) {
		logger.error("Context initialization failed", ex);
		throw ex;
	}
}
/**
 * 初始化应用
 */
protected WebApplicationContext initWebApplicationContext() {
       //获取应用上下文
	WebApplicationContext rootContext =
			WebApplicationContextUtils.getWebApplicationContext(getServletContext());
	WebApplicationContext wac = null;

	if (this.webApplicationContext != null) {
		// 上下文在构造时已经注入则直接使用
		wac = this.webApplicationContext;
		if (wac instanceof ConfigurableWebApplicationContext) {
			ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
			if (!cwac.isActive()) {
				//如果还么有父上下文,则设置父上下文为根上下文
				if (cwac.getParent() == null) {
					cwac.setParent(rootContext);
				}
                                // 配置并刷新应用    
				configureAndRefreshWebApplicationContext(cwac);
			}
		}
	}
        // 如果不存在上下文,查找现有的上下文
	if (wac == null) {
		wac = findWebApplicationContext();
	}
         //需要创建一个Servlet的上下文,初始化上下文的设置   
	if (wac == null) {
		// No context instance is defined for this servlet -> create a local one
		wac = createWebApplicationContext(rootContext);
	}
        //  刷新上下文,这里的onRefresh方法在DispatcherServlet中进行实现  
	if (!this.refreshEventReceived) {
		synchronized (this.onRefreshMonitor) {
			onRefresh(wac);
		}
	}
         //获取Servlet上下文,设置上下文属性。   
	if (this.publishContext) {
		String attrName = getServletContextAttributeName();
		getServletContext().setAttribute(attrName, wac);
	}
	return wac;
}
  • DispatcherServlet

    • 主要是解析器的初始化,总共有一下几种解析器

@Override
protected void onRefresh(ApplicationContext context) {
	initStrategies(context);
}

//进行初始化
protected void initStrategies(ApplicationContext context) {
	initMultipartResolver(context);//初始化文件上传解析器
	initLocaleResolver(context);//本地化解析器(多语言切换使用)
	initThemeResolver(context);//当前主题解析
	initHandlerMappings(context);//beanNameURL进行映射
	initHandlerAdapters(context);//controller进行映射
	initHandlerExceptionResolvers(context);//异常解析器
	initRequestToViewNameTranslator(context);//请求URI转视图名称解析器
	initViewResolvers(context);//视图解析器
	initFlashMapManager(context);//FlashMap管理
}

接收发送来的请求

  • FrameworkServlet

    • 提供了接收请求的实现方法,提供了入口;

    • 提供了请求的大致流程,具体如下源码中进行了分析;

    • 请求URL业务处理在DispatcherServlet中进行完成,后续代码中会进行分析。

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
    processRequest(request, response);
}
/**
 * 主要流程:
 * 1.创建localContext多语言切换实例
 * 2.从Request上下文处理器中获取request参数
 * 3.注册拦截器
 * 4.初始化上下文处理器,后续请求参数和多语言切换进行处理
 * 5.doService处理的是核心的URL隐射业务,这块业务在DispatcherServlet实现
 * 6.如果有异常则抛出异常
 * 7.请求处理完,则将上下文重置;打印请求日志
 * 8.异步执行应用的监听事件 
 */
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	long startTime = System.currentTimeMillis();
	Throwable failureCause = null;
        //获取本地语言上下文
	LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        // 获取request新传入的语言
	LocaleContext localeContext = buildLocaleContext(request);
        //从Request上下文获取请求参数
	RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        //请求参数转换为ServletRequest的请求参数类型
	ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
        
        //新建通过管理及注册回调拦截器     
	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
	asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
        // 初始化上下文    
	initContextHolders(request, localeContext, requestAttributes);

	try {
		doService(request, response);//子类进行实现
	}catch (ServletException | IOException ex) {
		failureCause = ex;
		throw ex;
	}catch (Throwable ex) {
		failureCause = ex;
		throw new NestedServletException("Request processing failed", ex);
	}finally {
                //重置上下文
		resetContextHolders(request, previousLocaleContext, previousAttributes);
                //进行回调  
		if (requestAttributes != null) {
			requestAttributes.requestCompleted();
		}
                //打印响应的结果  
		logResult(request, response, failureCause, asyncManager);
                //异步执行应用监听事件  
		publishRequestHandledEvent(request, response, startTime, failureCause);
	}
}

//request完成
public void requestCompleted() {
        //执行Request回调    
	executeRequestDestructionCallbacks();
       //更新session权限
	updateAccessedSessionAttributes();
	this.requestActive = false;
}

private void logResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable Throwable failureCause, WebAsyncManager asyncManager) {

	if (!logger.isDebugEnabled()) {
		return;
	}
        //转发类型    
	String dispatchType = request.getDispatcherType().name();
	boolean initialDispatch = request.getDispatcherType().equals(DispatcherType.REQUEST);

	if (asyncManager.isConcurrentHandlingStarted()) {
		logger.debug("Exiting but response remains open for further handling");
		return;
	}
       // 下面都是日志打印,省略代码。。。。。。	
}

  • DispatcherServlet(请求业务的核心处理部分)

    • 核心在于,根据MethodHandler,生成ModelAndView 或存入response
/**
 * 作用:1.格式化请求参数,派发请求任务到对应的方法处理
 */
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	logRequest(request);

	Map<String, Object> attributesSnapshot = null;
	if (WebUtils.isIncludeRequest(request)) {//当请求有URI的时候,格式化请求参数
		attributesSnapshot = new HashMap<>();
		Enumeration<?> attrNames = request.getAttributeNames();
		while (attrNames.hasMoreElements()) {
			String attrName = (String) attrNames.nextElement();
			if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
				attributesSnapshot.put(attrName, request.getAttribute(attrName));
			}
		}
	}

	// 设置请求参数
	request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
	request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
	request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
	request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

	if (this.flashMapManager != null) {
		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
		if (inputFlashMap != null) {
			request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
		}
		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
		request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
	}

	try {   //进行转发,也是核心方法   
		doDispatch(request, response);
	}
	finally {//重置request的属性
		if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Restore the original attribute snapshot, in case of an include.
			if (attributesSnapshot != null) {
				restoreAttributesAfterInclude(request, attributesSnapshot);
			}
		}
	}
}

/**
 * 这里的主要处理过程是这样的:
 * 1.先判断是不是multipart 请求,如果是要进行标记,等处理完之后要进行清空
 * 2.判断能否找到request对应的handler处理器(一般都是url请求都是RequestMappingHandlerMapping),如果查找不到直接返回404;
 * 3.查找对应请求的处理适配器(一般的都是RequestMappingHandlerAdapter)
 * 4.判断如果是GET请求方式,且最后次修改没有变化,直接返回
 * 5.执行拦截器的pre方法,如果存在异常直接返回;
 * 6.处理器适配器进行业务处理返回ModelAndView,如果ModelAndView非空,且没有View的情况下
 * 7.处理拦截器的post方法 
 * 8.出现异常之后,处罚拦截器的complete方法  
 * 9.如果是multipart Request的话,进行清空请求数据
 */ 
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	HandlerExecutionChain mappedHandler = null;
	boolean multipartRequestParsed = false;

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

	try {
		ModelAndView mv = null;
		Exception dispatchException = null;

		try {
			processedRequest = checkMultipart(request);//判断请求是否为上传文件,如果是文件则进行解析
			multipartRequestParsed = (processedRequest != request);

			// 查找当前请求的mappedHandler,下面有分析
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {//映射为空的时候,返回404 错误。
				noHandlerFound(processedRequest, response);
				return;
			}

			/**
                         * 查找对应的Handler适配器,一般有对应的controller解析,还有requestMapping解析等
                         */     
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// 检测最后修改头,检查请求头是否存在问题,存在问题直接返回
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}
                        //在这里执行拦截器(interceptor),如果执行错误则,返回
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			//执行映射的处理器,是核心部分。后面单独分析
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}
                        //如果ModelAndView中没有View,则返回请求的url
			applyDefaultViewName(processedRequest, mv);

                        // 拦截器执行postHandler方法
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		catch (Throwable err) {
			dispatchException = new NestedServletException("Handler dispatch failed", err);
		}
                /**
                 * 这里的代码不详细分析,大概执行过程如下:
                 * 1.判断是否有异常,如果有异常,按照ModelAndViewDefiningException生成对应的ModelAndView
                 * 2.判断是否有View视图要render,如果有,根据自己配置的渲染方式html,或者thymeleaf进行对应的渲染
                 */   
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
                //出现错误,进行处罚任务完成处理  
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Throwable err) {
                //出现错误,进行处罚任务完成处理  
		triggerAfterCompletion(processedRequest, response, mappedHandler,
				new NestedServletException("Handler processing failed", err));
	}
	finally {
                //同步管理,判断当前的请求是同步启动则,进行响应的拦截器处理  
		if (asyncManager.isConcurrentHandlingStarted()) {
			if (mappedHandler != null) {
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			}
		}
		else {
			// 清空中 multipart request 中的文件信息
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}
}


//获取mappedHandler的具体方法
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	Object handler = getHandlerInternal(request);//获取内部的handler
	if (handler == null) {
		handler = getDefaultHandler();
	}
	if (handler == null) {
		return null;
	}
	// 如果处理器是字符串从工厂中招对应的bean
	if (handler instanceof String) {
		String handlerName = (String) handler;
		handler = obtainApplicationContext().getBean(handlerName);
	}
        // 获取执行链,也即MappedInteraptor相关操作  
	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        //如果有跨域的配置时,重新调整执行链    
	if (hasCorsConfigurationSource(handler)) {
		CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		config = (config != null ? config.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}

	return executionChain;
}

//获取对应的HandlerMethod
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //对Request中的请求url进行解析请求url
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	request.setAttribute(LOOKUP_PATH, lookupPath);
	this.mappingRegistry.acquireReadLock();
	try {    //这里是重点:获取对应的handlerMethod (包含请求uri对应的类及方法)
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}

HandlerAdapter进行映射(以RequestMappingHandlerAdapter为例)

  • 这里是所有操作的核心所在,主要是,根据URI进行解析查找对应的方法,返回结果进行封装(代码细节太多没有解析)
# AbstractHandlerMethodAdapter
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	return handleInternal(request, response, (HandlerMethod) handler);
}

// 作用:处理uri映射
protected ModelAndView handleInternal(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
        //检查请求头是否允许    
	checkRequest(request);

	//判断session是否要加锁,并执行映射处理方法
	if (this.synchronizeOnSession) {
	   //省略一部分代码。。。。。。。。。。	
	}else {
                //执行处理的方法  
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}
          //判断请求头是否cache设置,设置response信息  
	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			prepareResponse(response);
		}
	}

	return mav;
}

/**
 * 作用:
 *  1.查找bean对应的方法invocableMethod 
 *  2.通过反射执行方法;
 *  3.将获取到的结果进行封装,并返回ModelAndView.
 */
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {   /**
                 * 将bean与对应的method进行绑定
                 * 将method设置参数解析器
                 */     
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
                /**
                 * 1.获取bean类路径,查看是否有model请求中是否有,以bean类路径为key的访问,没有则初始化
                 * 2.model访问缓存中如果已经有了这个bean路径,则将对应的方法加入
                 * 3.新键一个ModelFactory
                 */           
		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);
                //ModelView容器进行初始化  
		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);
                 //执行映射,这里执行对应方法的映射,下面有分析 
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}
                //这一步就是设置Model和View,如果Redirect则进行重定向  
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
                //request进行销毁  
		webRequest.requestCompleted();
	}
}



//执行url映射,这里是核心的方法。
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {
         //这里就是执行任务并且返回结果   
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        //设置响应的状态码    
	setResponseStatus(webRequest);
         //判断返回值,如果没数据,或者response有返回原因,则设置请求跳转为true,否则设置为false   
	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			disableContentCachingIfNecessary(webRequest);
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}

	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
        //将返回数据进行格式化
	try {
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}


//执行方法的具体过程
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));
	}
        /**
         * 这里不具体分析里面的过程,其实就是通过反射调用方法,获取方法执行结果   
         * 再将执行的结果进行封装,有不同的封装解析器
         * RequestResponseBodyMethodProcessor这个类提供了将返回的数据进行格式化ServletServerHttpResponse的方法
         * 如果不需要ViewAndModel变量,会将requestHandled参数设置为true,表示程序已经处理,不需要视图。 
         */ 
	return doInvoke(args);
}

拦截器的执行过程

  • 上面源码分析的过程中,已经分析了拦截器的执行过程,这些主要分析一下拦截器pre方法的执行逻辑;

    • 拦截器的任一pre前置方法返回false,则触发拦截器的afterCompletion方法
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];
                        //执行拦截器前置操作,返回true则继续,false的话进入方法里面
			if (!interceptor.preHandle(request, response, this.handler)) {
				triggerAfterCompletion(request, response, null);
				return false;
			}
			this.interceptorIndex = i;
		}
	}
	return true;
}

//触发完成后拦截器操作
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
		throws Exception {
	HandlerInterceptor[] interceptors = getInterceptors();
	if (!ObjectUtils.isEmpty(interceptors)) {
		for (int i = this.interceptorIndex; i >= 0; i--) {
			HandlerInterceptor interceptor = interceptors[i];
			try {    
                              //执行完成后操作      
			      interceptor.afterCompletion(request, response, this.handler, ex);
			}
			catch (Throwable ex2) {
				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
			}
		}
	}
}


总结

1. springmvc的重要组件有哪些?都有什么作用?

  这个问题,其实在我们前面解析源码的时候就已经看到了。DispatcherServlet初始化的时候,初始化的几个解析器都是常使用的组件。
  
  其中使用频率比较多的就是:
   
  1.HandlerMapping解析器,处理请求URI和对应方法的映射关系的处理器;

  2.HandlerAdapter解析器,根据HandleMapping进行对应方法调用处理的解析器;

  3.ViewResolver视图解析器,因为现在前后端分离其实很少使用了。

原文地址:https://www.cnblogs.com/perferect/p/13803990.html