SpringMVC源码解析

文章目录

    • 一、主要组件
    • 二、DispatcherServlet初始化过程
      • 1)结构体系
      • 2)通过requestMapping注解(url)获取controller
  • 总结:
    • 三、DispatcherServlet处理请求过程
      • 2)获取处理器映射器
    • 结果
      • 2)处理器适配器
      • 3)视图渲染
  • ==总结==

一、主要组件

  • DispatcherServlet:前端控制器,统一处理请求和响应,整个流程控制的中心,由它调用其他组件处理用户请求。
  • HandlerMapping:处理器映射器,根据请求的url、method等信息查找Handler,及控制器方法
  • Handler:处理器,及Controller方法,具体业务实现
  • HandlerAdpter:处理器适配器,对处理器方法进行执行
  • ViewRsolver:视图解析器,进行视图解析,如ThymeleafView、InternalResourceView
  • View:视图,及页面

二、DispatcherServlet初始化过程

1)结构体系

SpringMVC源码解析_第1张图片
Servlet接口init初始化方法

public interface Servlet {
    void init(ServletConfig var1) throws ServletException;
}

GenericServlet抽象类,初始化方法空实现(由子类重写实现)

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    public void init() throws ServletException {
    }
}

GenericServlet抽象类的子类HttpServlet没有实现,具体实现在HttpServletBean类
根据代码可知,具体实现依然需要子类根据需求喜好自己实现重写

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
	@Override
	public final void init() throws ServletException {
		//让子类做他们喜欢的任何初始化
		initServletBean();
	}
	protected void initServletBean() throws ServletException {
	}
}

FrameworkServlet 抽象类重写初始化方法initServletBean()
‘springMVC’ :项目名称。日志打印初始化servlet名称以及初始化所需时间

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
	@Override
	protected final void initServletBean() throws ServletException {
		//日志打印Initializing Spring DispachServlet 'springMVC'
		getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
		if (logger.isInfoEnabled()) {
			//日志打印Initializing Servlet 'springMVC'
			logger.info("Initializing Servlet '" + getServletName() + "'");
		}
		long startTime = System.currentTimeMillis();
		try {
			//初始化容器
			this.webApplicationContext = initWebApplicationContext();
			//空实现,由子类重写
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}
		//记录初始化所需时间
		if (logger.isInfoEnabled()) {
			logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
		}
	}
}

初始化webApplicationContext容器

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()) {
				// The context has not yet been refreshed -> provide services such as
				// setting the parent context, setting the application context id, etc
				if (cwac.getParent() == null) {
					// The context instance was injected without an explicit parent -> set
					// the root application context (if any; may be null) as the parent
					cwac.setParent(rootContext);
				}
				configureAndRefreshWebApplicationContext(cwac);
			}
		}
	}
	if (wac == null) {
		// No context instance was injected at construction time -> see if one
		// has been registered in the servlet context. If one exists, it is assumed
		// that the parent context (if any) has already been set and that the
		// user has performed any initialization such as setting the context id
		wac = findWebApplicationContext();
	}
	if (wac == null) {
		//创建WebApplicationContext
		wac = createWebApplicationContext(rootContext);
	}

	if (!this.refreshEventReceived) {
		//创建WebApplicationContext时候会添加监听器,onRefreash,DispatcherServlet初始化九大组件
		synchronized (this.onRefreshMonitor) {
			onRefresh(wac);
		}
	}

	if (this.publishContext) {
		// Publish the context as a servlet context attribute.
		String attrName = getServletContextAttributeName();
		getServletContext().setAttribute(attrName, wac);
	}

	return wac;
}

创建WebApplicationContext
XmlWebApplication类的父类实现了ConfigurableWebApplicationContext接口
WebApplicationContext的父容器是ApplicationContext

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
	//默认XmlWebApplication
	Class<?> contextClass = getContextClass();
	if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
		throw new ApplicationContextException(
				"Fatal initialization error in servlet with name '" + getServletName() +
				"': custom WebApplicationContext class [" + contextClass.getName() +
				"] is not of type ConfigurableWebApplicationContext");
	}
	//调用无参构造函数创建  ConfigurableWebApplicationContext 
	ConfigurableWebApplicationContext wac =
			(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	//设置环境参数
	wac.setEnvironment(getEnvironment());
	//设置springmvc的WebApplicationContext容器的父容器为spring的ApplicationContext容器 
	wac.setParent(parent);
	String configLocation = getContextConfigLocation();
	if (configLocation != null) {
		//设置‘springmvc.xml’配置文件路径
		wac.setConfigLocation(configLocation);
	}
	//配置刷新容器
	configureAndRefreshWebApplicationContext(wac);
	return wac;
}

配置刷新容器

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
	if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
		if (this.contextId != null) {
			wac.setId(this.contextId);
		}
		else {
            //就是把它的id由org.springframework.web.context.support.XmlWebApplicationContext@c335c0c
            //改成了基于Servlet名字的org.springframework.web.context.WebApplicationContext:/dispatcher,
            //官方文档说是替换成一个更有意义的ID
			wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
					ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
		}
	}
    //配置ServletContext,放进去的是ApplicationContextFacade对象
	wac.setServletContext(getServletContext());
	//配置ServletConfig,StandardWrapperFacade对象
	wac.setServletConfig(getServletConfig());
	//配置命名空间,默认是[Servlet的名字]-servlet
	wac.setNamespace(getNamespace());
	//添加监听器,监听ContextRefreshedEvent事件,该事件会在WebApplicationContext初始化完毕或者主动调用
    //refresh()方法时触发,比如Spring容器加载完context配置文件后就会触发,所以会触发多次,触发后调用
	wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

	//补全之前创建的StandardServletEnvironment对象
	ConfigurableEnvironment env = wac.getEnvironment();
	if (env instanceof ConfigurableWebEnvironment) {
		((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
	}
	//空方法,也是供子类扩展的,目前还没有使用
	postProcessWebApplicationContext(wac);
	//主要是为了在调用refresh方法之前做一些准备工作
	applyInitializers(wac);
	//主动调用refresh方法,触发上面刚添加的监听器
	wac.refresh();
}

DispatcherServlet初始化初始化九大组件

public class DispatcherServlet extends FrameworkServlet {
    @Override
    protected void onRefresh(ApplicationContext context) {
        //将初始化策略和onRefresh方法分开,让子类灵活扩展
        initStrategies(context);
    }
    //这也正是SpringMVC最为核心的部分
    protected void initStrategies(ApplicationContext context) {
        //处理文件上传请求
        initMultipartResolver(context);
        //国际化处理
        initLocaleResolver(context);
        //解析主题配置
        initThemeResolver(context);
        //把request映射到具体的处理器上(负责找handler)
        initHandlerMappings(context);
        //调用处理器来处理(负责让handler干活)
        initHandlerAdapters(context);
        //解析过程出了问题就交给我
        initHandlerExceptionResolvers(context);
        //从request中获取viewName
        initRequestToViewNameTranslator(context);
        //将我们返回的视图名字符串(如hello.jsp)解析为具体的view对象
        initViewResolvers(context);
        //管理FlashMap,主要用于redirect
        initFlashMapManager(context);
    }
}

2)通过requestMapping注解(url)获取controller

SpringMVC源码解析_第2张图片

  • InitializingBean接口
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
  • AbstractHandlerMethodMapping抽象类
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
	@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}
	protected void initHandlerMethods() {
		for (String beanName : getCandidateBeanNames()) {
			 判断不是已 scopedTarget 开头
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				processCandidateBean(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}
	//获取所有的bean名字
	protected String[] getCandidateBeanNames() {
		return (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
				obtainApplicationContext().getBeanNamesForType(Object.class));
	}
	protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
			// 获取具体的类型
			beanType = obtainApplicationContext().getType(beanName);
		}
		catch (Throwable ex) {
			// 不是null 并且 类型是存在 @Controller 或者 @RequestMapping  注解
			if (logger.isTraceEnabled()) {
				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
			}
		}
		if (beanType != null && isHandler(beanType)) {
			detectHandlerMethods(beanName);
		}
	}
}

核心代码来了

protected void detectHandlerMethods(Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

SpringMVC源码解析_第3张图片

总结:

Web容器启动后(发起调用),GenericServlet接收上下文对象,HttpServletBean给属性赋值,FrameworkServlet负责创建并初始化WebApplicationContext容器,最后DispatcherServlet初始化九大组件

三、DispatcherServlet处理请求过程

http://localhost:8080/springmvc/target

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

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

        try {
            //检查处理文件上传请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            //处理器映射器,根据url找到对应的controller,找不到报错
            mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}
            //根据controller找到对应的适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                //根据文件的最近修改时间判断是否返回304状态码,默认修改时间返回-1即不支持该缓存方式。
                //如果想使用需要另外配置
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            //处理前先执行拦截器的preHandle方法,该方法会返回一个boolean值
            //如果是true,则交给后面的Interceptor继续处理,返回false则表示自己处理完了,
            //包括response也搞定了,后面的不用麻烦了直接做中断处理。
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            //HandlerAdapter调用Handler处理请求
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            //判断是否需要viewNameTranslator从request里获取view的名字(针对在handler的返回值里没有给出的情况)
            applyDefaultViewName(request, mv);
            //处理完后执行拦截器的PostHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        //做最后的处理工作,比如页面渲染,调用拦截器的afterCompletion方法等
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
    }
    finally {
        //清理文件上传留下的临时文件
        if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
        }
    }
}

2)获取处理器映射器

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
			//通过url匹配controller具体方法
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

核心就是第一行代码

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	Object handler = getHandlerInternal(request);
	if (handler == null) {
		handler = getDefaultHandler();
	}
	if (handler == null) {
		return null;
	}
	// Bean name or resolved handler?
	if (handler instanceof String) {
		String handlerName = (String) handler;
		handler = obtainApplicationContext().getBean(handlerName);
	}

	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

	if (logger.isTraceEnabled()) {
		logger.trace("Mapped to " + handler);
	}
	else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
		logger.debug("Mapped to " + executionChain.getHandler());
	}

	if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
		CorsConfiguration config = getCorsConfiguration(handler, request);
		if (getCorsConfigurationSource() != null) {
			CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
			config = (globalConfig != null ? globalConfig.combine(config) : config);
		}
		if (config != null) {
			config.validateAllowCredentials();
		}
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}

	return executionChain;
}

核心步骤

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	//requestMapping地址如  “/target”
	String lookupPath = initLookupPath(request);
	this.mappingRegistry.acquireReadLock();
	try {
		//通过九大组件中获取的全量的controller匹配得到具体方法并返回
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}

结果

SpringMVC源码解析_第4张图片

2)处理器适配器

public interface HandlerAdapter {
	//是否支持该HandlerMethod
	boolean supports(Object handler);
	//HandlerMthod根据反射调用controller具体方法返回modelAndView
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	//最后修改时间
	long getLastModified(HttpServletRequest request, Object handler);
}

SpringMVC源码解析_第5张图片

  1. HttpRequestHandler:适配实现了HttpRequestHandler接口的handler
  2. SimpleServletHandlerAdapter:适配实现了Servlet接口的handler
  3. RequestMappingHandlerAdapter:适配通过@RequestMapping注解的handler。会封装为HandleMethod对象
  4. SimpleControllerHandlerAdapter:适配实现了Controller接口的handler

处理器适配器通过反射执行controller方法核心代码

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	//检查是否支持当前request的请求方式和session
	checkRequest(request);

	// 如果需要,在同步块中执行invokeHandlerMethod
	if (this.synchronizeOnSession) {
		HttpSession session = request.getSession(false);
		if (session != null) {
			Object mutex = WebUtils.getSessionMutex(session);
			synchronized (mutex) {
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No HttpSession available -> no mutex necessary
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
	}
	else {
		// No synchronization on session demanded at all...
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}

	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		//判断是否有@SessionAttribute注解
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			//准备响应工作
			prepareResponse(response);
		}
	}

	return mav;
}

调用具体方法

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	...
}

最难也是最主要的工作获取方法反射需要的参数(及方法请求的参数)

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    return this.doInvoke(args);
}

获取request、sesion、自定义对象等等参数值

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    MethodParameter[] parameters = this.getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    } else {
        Object[] args = new Object[parameters.length];

        for(int i = 0; i < parameters.length; ++i) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] == null) {
                if (!this.resolvers.supportsParameter(parameter)) {
                    throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                }

                try {
                    args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                } catch (Exception var10) {
                    if (logger.isDebugEnabled()) {
                        String exMsg = var10.getMessage();
                        if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                            logger.debug(formatArgumentError(parameter, exMsg));
                        }
                    }

                    throw var10;
                }
            }
        }

        return args;
    }
}

3)视图渲染

执行最后结果

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
		@Nullable 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);
		}
	}

	// 处理渲染
	if (mv != null && !mv.wasCleared()) {
		render(mv, request, response);
		if (errorView) {
			WebUtils.clearErrorRequestAttributes(request);
		}
	}
	else {
		if (logger.isTraceEnabled()) {
			logger.trace("No view rendering, null ModelAndView returned.");
		}
	}

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

	if (mappedHandler != null) {
		// 拦截器,页面渲染后调用
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}

具体渲染过程

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	// 国际化设置
	Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
	response.setLocale(locale);

	View view;
	String viewName = mv.getViewName();
	if (viewName != null) {
		// 获取视图解析器
		view = resolveViewName(viewName, 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.isTraceEnabled()) {
		logger.trace("Rendering view [" + view + "] ");
	}
	//
	try {
		if (mv.getStatus() != null) {
			response.setStatus(mv.getStatus().value());
		}
		//将model值渲染到页面上
		view.render(mv.getModelInternal(), request, response);
	}
	catch (Exception ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Error rendering view [" + view + "]", ex);
		}
		throw ex;
	}
}

view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
通过自己配置的视图解析器,
SpringMVC源码解析_第6张图片
view.render(mv.getModelInternal(), request, response);
将model值渲染到页面上

总结

  • DispatcherServlet中处理器映射器通过@RequestMapping注解找到对应的Controller方法
  • DispatcherServlet中处理器适配器拿着处理器映射器数据通过反射执行Controller方法并返回ModelAndView
  • DispatcherServlet中最后执行结果处理,通过配置的视图解析器为ModelAndView添加前缀后缀,再将model填充页面返回即可
  • 拦截器,执行Controller方法的前者方法,后置方法,渲染页面返回后执行的方法

你可能感兴趣的:(spring,spring,java)