文章目录

  • SpringMVC源码解析
    • SPI机制
      • 案例
      • SpringMVC中SPI的使用
      • 初始化IOC容器与九大组件
        • 初始化容器
        • 初始化九大组件
      • 小结
    • SpringMVC如何处理一个请求
      • doDispatch全流程
      • 【1】、上传文件检查
      • 【2】、构造HandlerExecutionChain
        • 关于HandlerMapping
        • 小结
      • 【3】、获取HandlerAdapter
        • 关于HandlerAdapter
        • 小结
      • 【4】、拦截器前置处理
        • 拦截器
        • 小结
      • 【5】、执行目标方法
        • 小结
      • 【6】、拦截器后置处理
      • 【7】、处理调度结果
      • 请求处理全流程小结
      • 两个知识点

SpringMVC源码解析

SPI机制

SPI机制,Service Provider Interface,是一种服务发现机制,能够通过定义接口+提供resource资源,让程序自动去资源中得到接口实现,并且加载。体现了面向接口编程,策略模式,配置文件组合的动态加载机制。

怎么用SPI机制:

1、定义接口

2、resource下创建META-INF/services,里面的文件名是接口的全限定类名,内容是实现类的全限定类名

3、主程序通过ServiceLoader加载实现类进jvm

4、SPI实现类必须携带无参构造器

案例

1、定义接口

public interface IMyLove {public void love();
}

2、创建实现类

public class BlackSiGirl implements IMyLove {@Overridepublic void love() {System.out.println("我爱穿黑丝的美女");}
}
public class LongLagGir implements IMyLove {@Overridepublic void love() {System.out.println("我爱大长腿的美女");}
}

3、启动类

public class Start {public static void main(String[] args) {//SPI机制:通过接口+resource =》加载对应的接口实现ServiceLoader<IMyLove> load = ServiceLoader.load(IMyLove.class);Iterator<IMyLove> iterator = load.iterator();while (iterator.hasNext()) {iterator.next().love();}}
}

4、配置文件

IMyLove

BlackSiGirl
LongLagGir

SpringMVC中SPI的使用

SpringMVC中也使用了SPI机制,接口ServletContainerInitializer的实现类会在Tomcat启动的时候自动加载。启动过程会调用onStartup方法。

SPI接口ServletContainerInitializer:

public interface ServletContainerInitializer {public void onStartup(Set<Class<?>> c, ServletContext ctx)throws ServletException;
}

SPI接口实现类SpringServletContainerInitializer:

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {@Overridepublic void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {List<WebApplicationInitializer> initializers = new LinkedList<>();if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {// Be defensive: Some servlet containers provide us with invalid classes,// no matter what @HandlesTypes says...//所有非接口,非抽象的WebApplicationInitializer的实现类,最终会被加载到initializersif (!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);}}}}if (initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");return;}servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);//遍历所有满足要求的initializer,调用onStartupfor (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}}

Tomcat一启动,就好加载全部满足要求的WebApplicationInitializer,并且调用其onStartup方法。也就是我们要实现WebApplicationInitializer,就可以完成自定义操作,我们就是在这里完成IOC容器的启动和DispatcherServlet的创建,并将DispatcherServlet加到到ServletContext上。

现在我们来实现Tomcat一启动,就自动创建IOC和DispatcherServlet的操作:

1、实现DispatcherServlet

public class AppStarter implements WebApplicationInitializer {@Overridepublic void onStartup(javax.servlet.ServletContext servletContext) throws ServletException {// 创建IOC容器AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();// 加载配置类context.register(AppConfig.class);//此时IOC容器还没有进行refresh,留给后续servlet的init逻辑refresh// 创建DispatcherServletDispatcherServlet servlet = new DispatcherServlet(context);ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);registration.setLoadOnStartup(1);registration.addMapping("/");//DispatcherServlet添加到ServletContext之后,Tomcat会对其进行初始化}
}

该类会在SpringServletContainerInitializer通过SPI机制加载调用onStartup方法加载,同时创建IOC容器与DispatcherServlet。DispatcherServlet创建完成后加载到ServletContext之后,Tomcat会对其初始化,这里就涉及到了servlet的生命周期,自定义的servlet加载到ServletContext之后,会由Tomcat调用init方法,进行初始化。

补充一下servlet的生命周期:init初始化,service处理请求,destroy(tomcat停止使用调用destroy销毁)

2、配置类

@ComponentScan(basePackages = "com.sfan.controller")
@Configuration
public class AppConfig {}

3、controller

@RestController
public class HellloController {@GetMapping("/hello")public String hello(){return "hello,spring mvc";}
}

初始化IOC容器与九大组件

1、执行HttpServletBean.init()

 @Overridepublic final void init() throws ServletException {// Set bean properties from init parameters.PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);if (!pvs.isEmpty()) {try {BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);}catch (BeansException ex) {if (logger.isErrorEnabled()) {logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);}throw ex;}}// Let subclasses do whatever initialization they like.//主要逻辑initServletBean();}

可以看到,主要的逻辑在initServletBean()在这里,这个逻辑使用模板方法留给了子类实现。

2、FrameworkServlet.initServletBean()

@Overrideprotected final void initServletBean() throws ServletException {getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");if (logger.isInfoEnabled()) {logger.info("Initializing Servlet '" + getServletName() + "'");}long startTime = System.currentTimeMillis();try {//初始化IOC容器this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();}catch (ServletException | RuntimeException ex) {logger.error("Context initialization failed", ex);throw ex;}if (logger.isDebugEnabled()) {String value = this.enableLoggingRequestDetails ?"shown which may lead to unsafe logging of potentially sensitive data" :"masked to prevent unsafe logging of potentially sensitive data";logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +"': request parameters and headers will be " + value);}if (logger.isInfoEnabled()) {logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");}}

存在核心逻辑initWebApplicationContext,能够完成初始化IOC容器和九大组件

3、FrameworkServlet.initWebApplicationContext()

protected WebApplicationContext initWebApplicationContext() {//父容器WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;if (this.webApplicationContext != null) {//当前的web-ioc容器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();}if (wac == null) {wac = createWebApplicationContext(rootContext);}if (!this.refreshEventReceived) {synchronized (this.onRefreshMonitor) {//初始化9大组件onRefresh(wac);}}if (this.publishContext) {// Publish the context as a servlet context attribute.String attrName = getServletContextAttributeName();getServletContext().setAttribute(attrName, wac);}return wac;}

该方法中有两个核心的内容一个是初始化IOC容器,一个是初始化的九大组件

初始化IOC容器:configureAndRefreshWebApplicationContext

初始化九大组件:onRefresh

初始化容器

4、初始化IOC容器

FrameworkServlet#configureAndRefreshWebApplicationContext

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {if (ObjectUtils.identityToString(wac).equals(wac.getId())) {if (this.contextId != null) {wac.setId(this.contextId);}else {wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());}}wac.setServletContext(getServletContext());wac.setServletConfig(getServletConfig());wac.setNamespace(getNamespace());wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));ConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());}postProcessWebApplicationContext(wac);applyInitializers(wac);//初始化容器的正式逻辑wac.refresh();}

AbstractApplicationContext#refresh

@Overridepublic void refresh() throws BeansException, IllegalStateException {//加锁是因为容器只有一个,防止重复创建synchronized (this.startupShutdownMonitor) {//刷新容器预准备工作//获取当前系统时间,给容器设置同步锁标识prepareRefresh();//注册bd,获取beanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//beanFactory预处理操作prepareBeanFactory(beanFactory);try {//空方法,留给子类实现,用于注册一些BeanFactoryPostProcessorpostProcessBeanFactory(beanFactory);//beanDefinition信息加载完之后执行beanFactoryPostProcessor,加载bean之前执行,主要用于添加删除修改BeanDefinition//执行了的后处理器器是BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor//执行的过程是先执行BeanDefinitionRegistryPostProcessor//最后按照先次非顺序执行自定义的BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);//注册后处理器registerBeanPostProcessors(beanFactory);//国际化(忽略)initMessageSource();//初始化事件传播器initApplicationEventMulticaster();//空方法。留给子类实现。这个方法内可以硬编码提供一些组件//比如:提供一些监听器ListeneronRefresh();//注册Listener(onRefresh中的硬编码Listener和配置文件注册的bd)监听器到Multicaster中registerListeners();//实例化非懒加载状态的单实例finishBeanFactoryInitialization(beanFactory);//完成刷新后做的一些事情。主动是启动生命周期对象finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}destroyBeans();cancelRefresh(ex);throw ex;}finally {resetCommonCaches();}}}

熟悉的spring容器启动代码,正式完成容器的初始化

初始化九大组件

5、初始化九大组件

DispatcherServlet#onRefresh

 @Overrideprotected void onRefresh(ApplicationContext context) {initStrategies(context);}

DispatcherServlet#initStrategies

 //初始化所有策略,九大组件//如果不满足9大组件,可以自定义并且放在ioc容器中,springmvc启动就会加载我们自定义的组件protected void initStrategies(ApplicationContext context) {initMultipartResolver(context); //容器中获取,没有就是nullinitLocaleResolver(context); //容器中获取,没有就用默认initThemeResolver(context); //容器中获取,没有就用默认initHandlerMappings(context); //容器中获取,没有就用默认initHandlerAdapters(context); //容器中获取,没有就用默认initHandlerExceptionResolvers(context); //容器中获取,没有就用默认initRequestToViewNameTranslator(context); //容器中获取,没有就用默认initViewResolvers(context); //容器中获取,没有就用默认initFlashMapManager(context); //容器中获取,没有就用默认}

这里存在一个问题,如果我们提供自定义的到容器中去,就会覆盖掉默认的,这也是后面Springboot要解决的,后文继续。

DispatcherServlet的九大组件

 //文件上传解析器@Nullableprivate MultipartResolver multipartResolver;//国际化解析@Nullableprivate LocaleResolver localeResolver;//主题解析器@Nullableprivate ThemeResolver themeResolver;//Handler(处理器,能处理请求的人【controller】)的映射//保存的是所有请求都是谁处理的映射关系:找到Handler的@Nullableprivate List<HandlerMapping> handlerMappings;//Handler(处理器,能处理请求的人【controller】)的适配器//超级反射工具:调用方法的@Nullableprivate List<HandlerAdapter> handlerAdapters;//Handler的异常解析器,处理异常功能@Nullableprivate List<HandlerExceptionResolver> handlerExceptionResolvers;//把请求转换成视图名(我们要跳转的页面地址)的翻译器@Nullableprivate RequestToViewNameTranslator viewNameTranslator;//闪存管理器(保存redirect的数据)@Nullableprivate FlashMapManager flashMapManager;//视图解析器(我们要去哪些页面,怎么过去)@Nullableprivate List<ViewResolver> viewResolvers;

小结

SpringMVC如何启动初始化IOC和九大组件的?

首先启动Tomcat的时候,会使用SPI机制,调用ServletContainerInitializer的实现类SpringServletContainerInitializer#onStartup方法,该方法会得到所有能够匹配的WebApplicationInitializer接口实现类,我们也就是在这个实现类中完成了IOC容器的刷新和DispatcherServlet的创建,并且挂载到ServletContext上,具体的IOC容器的刷新和DispatcherServlet九大组件的初始化交给了Tomcat调用Servlet的init方法。

关于init方法,入口是HttpServletBean中的init方法,该方法会调用FrameworkServlet子类实现的initServletBean()方法,该方法继续调用initWebApplicationContext方法,在configureAndRefreshWebApplicationContext方法中完成IOC容器的刷新,在onRefresh中完成DispatcherServlet九大组件的初始化。

SpringMVC如何处理一个请求

客户端所有的请求,会调用FrameworkServlet#service方法,最终会打到DispatcherServlet上,会调用其doDispatch方法对请求处理,这是SpringMVC请求处理的核心。

doDispatch全流程

 //springmvc 请求处理核心protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {//需要处理的请求HttpServletRequest processedRequest = request;//handler(目标方法)的执行链//存在handler(目标方法) + interceptorList(拦截器链) + interceptorIndex(拦截器执行到哪个的下标)HandlerExecutionChain mappedHandler = null;//文件上传标志位//false:不是文件上传//true:是文件上传boolean multipartRequestParsed = false;//对异步请求的支持(servlet3.0以后才有)WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {//ModelAndView:ModelMap(给页面的数据) + View(要前往的页面viewName) + HttpStatus(响应的状态码)ModelAndView mv = null;//异常的引用Exception dispatchException = null;try {//【1】、检查是否是文件上传processedRequest = checkMultipart(request);//条件成立:说明请求经过处理,因此是文件上传请求multipartRequestParsed = (processedRequest != request);// 【2】、构造了【目标方法+拦截器整个链路】决定使用哪个Handler处理当前的请求//HandlerExecutionChain:mappedHandlermappedHandler = getHandler(processedRequest);//条件成立:说明没有可以处理该请求的方法(handler)if (mappedHandler == null) {//抛出NoHandlerFoundException 或者 返回404错误页面noHandlerFound(processedRequest, response);return;}//【3】、根据handler请求处理方法 =》获取适配器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;}}//【4】、拦截器前置拦截过程//条件成立:存在拦截器中断执行返回了false,请求结束,直接returnif (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}//【5】调用超级反射器HandlerAdapter来真正执行目标方法mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}//没有指定viewName的情况下:为ModelAndView设置默认的viewNameapplyDefaultViewName(processedRequest, mv);//【6】拦截器的后置处理//controller执行完之后,视图渲染之前,执行拦截器的后置处理,可以对modelAndView进行修改mappedHandler.applyPostHandle(processedRequest, response, mv);}//记录异常catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {dispatchException = new NestedServletException("Handler dispatch failed", err);}//【7】、异常的处理 和 视图的渲染//来到这里,请求已经执行完毕,剩下的就是渲染view//处理结果:包含处理异常,返回ModelAndViewprocessDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}//进入catch说明在异常处理和渲染视图中出现了异常,调用拦截器的afterCompletioncatch (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 {//条件成立:说明是文件上传请求if (multipartRequestParsed) {//清除上传过程中的临时文件cleanupMultipart(processedRequest);}}}}

【1】、上传文件检查

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {//条件成立:说明multipartResolver存在,并且是multipart类型if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");}}else if (hasMultipartException(request)) {logger.debug("Multipart resolution previously failed for current request - " +"skipping re-resolution for undisturbed error rendering");}else {try {//使用multipartResolver文件上传解析器解析请求return this.multipartResolver.resolveMultipart(request);}catch (MultipartException ex) {if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {logger.debug("Multipart resolution failed for error dispatch", ex);// Keep processing error dispatch with regular request handle below}else {throw ex;}}}}//来到这里,说明请求不是上传文件请求return request;}

【2】、构造HandlerExecutionChain

             // Determine handler for the current request.// 【2】、构造了【目标方法+拦截器整个链路】决定使用哪个Handler处理当前的请求//HandlerExecutionChain:mappedHandlermappedHandler = getHandler(processedRequest);//条件成立:说明没有可以处理该请求的方法(handler)if (mappedHandler == null) {//抛出NoHandlerFoundException 或者 返回404错误页面noHandlerFound(processedRequest, response);return;}

DispatcherServlet#getHandler

 //所有策略模式,尝试所有策略@Nullableprotected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {//根据request去获取HandlerExecutionChain(重点关注RequestMappingHandlerMapping类)HandlerExecutionChain handler = mapping.getHandler(request);//返回第一个handlerif (handler != null) {return handler;}}}return null;}

策略模式,遍历HandlerMapping,去寻找匹配的HandlerMapping去getHandler(request)

AbstractHandlerMapping#getHandler

@Override@Nullablepublic final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//HandlerMapping的registry中找映射,返回真正能够执行请求的方法//返回的是HandlerMethod,包装了核心的controller和执行的methodObject handler = getHandlerInternal(request);if (handler == null) {//获取默认的Handlerhandler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;//容器中获取handlerhandler = obtainApplicationContext().getBean(handlerName);}//经过以上操作,就找到了handler(HandlerMethod)//找到目标方法后,还要构建处理器链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 = (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:

public class HandlerMethod {/** Logger that is available to subclasses. */protected final Log logger = LogFactory.getLog(getClass());//自定义的controller对象private final Object bean;@Nullableprivate final BeanFactory beanFactory;private final Class<?> beanType;//能够处理当前请求的方法private final Method method;private final Method bridgedMethod;private final MethodParameter[] parameters;@Nullableprivate HttpStatus responseStatus;@Nullableprivate String responseStatusReason;@Nullableprivate HandlerMethod resolvedFromHandlerMethod;@Nullableprivate volatile List<Annotation[][]> interfaceParameterAnnotations;private final String description;
}
关于HandlerMapping

常用实现:

  • AbstractHandlerMapping
  • AbstractUrlHandlerMapping
  • SimpleUrlHandlerMapping
  • BeanNameUrlHandlerMapping
  • RequestMappingHandlerMapping

以RequestMappingHandlerMapping为例分析

既然是九大组件之一,那么就是initStrategies处开始初始化。

DispatcherServlet#initStrategies

 //初始化所有策略,九大组件//如果不满足9大组件,可以自定义并且放在ioc容器中,springmvc启动就会加载我们自定义的组件protected void initStrategies(ApplicationContext context) {initMultipartResolver(context); //容器中获取,没有就是nullinitLocaleResolver(context); //容器中获取,没有就用默认initThemeResolver(context); //容器中获取,没有就用默认initHandlerMappings(context); //容器中获取,没有就用默认initHandlerAdapters(context); //容器中获取,没有就用默认initHandlerExceptionResolvers(context); //容器中获取,没有就用默认initRequestToViewNameTranslator(context); //容器中获取,没有就用默认initViewResolvers(context); //容器中获取,没有就用默认initFlashMapManager(context); //容器中获取,没有就用默认}

DispatcherServlet#initHandlerMappings

 private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}else {try {//默认初始化HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);this.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}// Ensure we have at least one HandlerMapping, by registering// a default HandlerMapping if no other mappings are found.if (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerMappings declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}

调用了getBean方法,大概会进行createBean,暴露早期实例,属性合并,属性填充,调用初始化方法(在这里调用了afterPropertiesSet,扫描了所有的controller的method,封装成为了HandlerMethod并且进行映射存放到了mappingRegistry中

AbstractHandlerMethodMapping#afterPropertiesSet

 @Overridepublic void afterPropertiesSet() {initHandlerMethods();}

AbstractHandlerMethodMapping#initHandlerMethods

 protected void initHandlerMethods() {//getCandidateBeanNames():获取容器中所有的beanName//对每一个bean进行遍历,并且注册mapping与handlerMethod在mappingRegistry的映射for (String beanName : getCandidateBeanNames()) {//排除以scopedTarget.开头的beanif (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {//处理当前的beanName,去建立映射关系processCandidateBean(beanName);}}handlerMethodsInitialized(getHandlerMethods());}

AbstractHandlerMethodMapping#processCandidateBean

 protected void processCandidateBean(String beanName) {Class<?> beanType = null;try {//获取beanName的类型beanType = obtainApplicationContext().getType(beanName);}catch (Throwable ex) {if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex);}}//条件成立:类型不为空 并且 【类上存在@Controller 或者 @RequestMapping 注解】if (beanType != null && isHandler(beanType)) {//建立mapping和handlerMethod的映射关系detectHandlerMethods(beanName);}}

AbstractHandlerMethodMapping#detectHandlerMethods

 //handler:传入的beanNameprotected void detectHandlerMethods(Object handler) {//获取当前handler的类型Class<?> handlerType = (handler instanceof String ?obtainApplicationContext().getType((String) handler) : handler.getClass());if (handlerType != null) {//针对CGLIB生成的子类,找到用户真正定义的类型userTypeClass<?> 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);//将mapping和handlerMethod注册到mappingRegistry中registerHandlerMethod(handler, invocableMethod, mapping);});}}

RequestMappingHandlerMapping#registerHandlerMethod

 @Overrideprotected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {super.registerHandlerMethod(handler, method, mapping);updateConsumesCondition(mapping, method);}

AbstractHandlerMethodMapping#registerHandlerMethod

 //注册mapping和handlerMethod的映射protected void registerHandlerMethod(Object handler, Method method, T mapping) {this.mappingRegistry.register(mapping, handler, method);}

真正注册映射关系的地方mappingRegistry

AbstractHandlerMethodMapping

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {//存放uri对应controller的对应方法private final MappingRegistry mappingRegistry = new MappingRegistry();
}
小结

1、HandlerMapping的作用是将请求的request,通过遍历所有的HandlerMapping.getHandler,获取HandlerMethod,将得到的HandlerMethod构造成处理器链HandlerExecutionChain(也就是带着拦截器链和handlerMethod)

2、RequestMappingHandlerMapping的构建过程:

①、九大组件都是从initStrategies中加载,在getBean的过程中,在走到初始化方法的时候,会调用afterPropertiesSet回调完成组件的初始化,RequestMappingHandlerMapping也不例外。

②、RequestMappingHandlerMapping在初始化过程中,扫描了所有的controller的method,封装成为了HandlerMethod作为value,mapping作为key,存放到了AbstractHandlerMethodMapping的mappingRegistry中

【3】、获取HandlerAdapter

HandlerAdapter是真正执行请求的组件

DispatcherServlet#doDispatch

             //【3】、根据handler请求处理方法 =》获取适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

DispatcherServlet#getHandlerAdapter

 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {// 策略模式// 遍历所有的HandlerAdapter去匹配能够supports handler的Handler// 拿到默认的所有适配器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");}

经过上述过程就得到了HandlerAdapter。

关于HandlerAdapter

看看这个HandlerDapter组件是啥样子的

//完成适配器加策略
public interface HandlerAdapter {//策略模式,匹配handlerboolean supports(Object handler);//处理过程,适配器的体现@NullableModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;long getLastModified(HttpServletRequest request, Object handler);
}

这里我们以RequestMappingHandlerAdapter为例分析

RequestMappingHandlerAdapter#afterPropertiesSet

@Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beans//初始化ControllerAdvice【异常处理相关的功能】initControllerAdviceCache();//条件成立:参数解析器为空if (this.argumentResolvers == null) {// 拿到底层的ArgumentResolverList<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();// 把这些resolver统一组合到一个对象里面,方便管控this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}//条件成立:initBinder参数解析器为空if (this.initBinderArgumentResolvers == null) {//获取底层的HandlerMethodArgumentResolverList<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}//条件成立:returnValueHandlers返回值处理器为空if (this.returnValueHandlers == null) {//获取底层的HandlerMethodReturnValueHandlerList<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}

RequestMappingHandlerAdapter#initControllerAdviceCache

//初始化ControllerAdvice【异常处理相关的功能】private void initControllerAdviceCache() {if (getApplicationContext() == null) {return;}//获取所有类上带@ControllerAdvice注解的beanList<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();//遍历所有带有@ControllerAdvice注解的beanfor (ControllerAdviceBean adviceBean : adviceBeans) {//获取其类型Class<?> beanType = adviceBean.getBeanType();if (beanType == null) {throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);}//获取所有标注了@ModelAttribute注解的方法Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);if (!attrMethods.isEmpty()) {this.modelAttributeAdviceCache.put(adviceBean, attrMethods);}//获取所有标注了@InitBinder注解的方法Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);if (!binderMethods.isEmpty()) {this.initBinderAdviceCache.put(adviceBean, binderMethods);}//是否实现了RequestBodyAdvice或者ResponseBodyAdvice接口if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {requestResponseBodyAdviceBeans.add(adviceBean);}}if (!requestResponseBodyAdviceBeans.isEmpty()) {this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);}if (logger.isDebugEnabled()) {int modelSize = this.modelAttributeAdviceCache.size();int binderSize = this.initBinderAdviceCache.size();int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {logger.debug("ControllerAdvice beans: none");}else {logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");}}}
小结

1、HandlerAdapter是一个超级反射器,我们拿到它就是为了参数解析(通过参数解析器获取参数值),方法执行和返回值处理

2、HandlerAdapter中有两个核心方法:supports和handle,前一个是策略器的体现,后一个是适配器的体现,也是方法执行的入口,核心在于参数的解析,方法的执行,返回值的封装。

3、在RequestMappingHandlerAdapter的afterPropertiesSet的过程中,主要是进行了对于@ControllerAdvice类下的一些方法的扫描,并且缓存;此外为其组合了参数解析器和返回值处理器。

【4】、拦截器前置处理

DispatcherServlet#doDispatch

//【4】、拦截器前置拦截过程
//条件成立:存在拦截器中断执行返回了false,请求结束,直接return
if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;
}

HandlerExecutionChain#applyPreHandle

 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)) {//触发afterCompletion,回收资源triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}}return true;}
拦截器
public interface HandlerInterceptor {//preHandle:在controller方法处理之前执行,intercepter按照顺序依次执行// 返回true继续执行;返回false中断请求,直接return请求不处理,也不执行controller方法,不会进入afterCompletiondefault boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}//执行完controller得到ModelView,但是DispatcherServlet还没有进行视图渲染之前,调用该方法//也就是可以在这个方法中对于ModelView进行处理修改default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}//在执行完视图渲染之后执行,多用于清理资源default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}}
小结

目标方法执行之前执行拦截器链前置处理,如果有一个拦截器返回了false,请求直接退出,不执行请求处理方法,并且触发afterCompletion回收资源。

【5】、执行目标方法

DispatcherServlet#doDispatch

//【5】调用超级反射器HandlerAdapter来真正执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

AbstractHandlerMethodAdapter#handle

 @Override@Nullablepublic final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return handleInternal(request, response, (HandlerMethod) handler);}

AbstractHandlerMethodAdapter#handleInternal

 @Overrideprotected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {//view:我们要去的页面(viewName)//model:我们给页面的数据ModelAndView mav;//判断请求类型以及是否需要携带sessioncheckRequest(request);//会话锁:每一个用户与服务器无论发了多少个请求,都只有一个会话。限制用户的线程if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {//可以限制用户一次进来一个请求//执行目标方法mav = invokeHandlerMethod(request, response, handlerMethod);}}else {//执行目标方法mav = invokeHandlerMethod(request, response, handlerMethod);}}else {//执行目标方法mav = invokeHandlerMethod(request, response, handlerMethod);}if (!response.containsHeader(HEADER_CACHE_CONTROL)) {//设置缓存的过期时间if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);}else {prepareResponse(response);}}//返回请求执行完毕之后的modelAndViewreturn mav;}

最终都是执行invokeHandlerMethod方法,也就是该方法是目标方法。

RequestMappingHandlerAdapter#invokeHandlerMethod

 @Nullableprotected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {//把原生的request和response封装到一个对象里,方便后续用一个对象就行【增强了 =》装饰器模式】ServletWebRequest webRequest = new ServletWebRequest(request, response);try {//数据绑定器:数据类型转换,绑定错误处理//请求数据到自定义Object属性的映射需要用到WebDataBinderFactory//处理initBinderMethod  WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);//获取模型工厂,Model:要交给页面的数据;View:要去的视图ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);//HandlerMethod封装成ServletInvocableHandlerMethod,提供HandlerMethod里面信息的快速获取//ServletInvocableHandlerMethod 能够进行 参数绑定,请求处理,返回值处理ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);//参数解析器:反射解析目标方法中每一个参数的值if (this.argumentResolvers != null) {invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}//返回值解析器:处理目标方法执行后的值。无论目标方法返回值是什么,都要想办法变成适配器能够使用的ModelViewif (this.returnValueHandlers != null) {invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);}invocableMethod.setDataBinderFactory(binderFactory);//设置参数名发现器invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);//以上的核心组件都挺重要//ModelAndViewContainer:模型和视图容器,把处理过程中产生的模型与视图有关的数据先放在这里//整个请求处理线程期间共享数据ModelAndViewModelAndViewContainer mavContainer = new ModelAndViewContainer();//将FlashMap中的数据保存在Model中mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));//使用modelFactory将sessionAttributes和@ModelAttributede的方法的参数设置到ModelmodelFactory.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);}//将要执行目标方法,执行期间的数据存在mavContainer//执行Controller中的RequestMapping注释的方法invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}//提取出ModelAndView准备返回//封装ModelAndViewreturn getModelAndView(mavContainer, modelFactory, webRequest);}finally {webRequest.requestCompleted();}}

ServletInvocableHandlerMethod#invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {//目标方法的反射执行过程Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);setResponseStatus(webRequest);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;}}

进入invokeForRequest,该方法是执行handler的核心

InvocableHandlerMethod#invokeForRequest

 @Nullablepublic 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);}

最关键的就是如何去解析参数,获取参数值。

InvocableHandlerMethod#getMethodArgumentValues

 protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {//拿到方法的所有参数MethodParameter[] parameters = getMethodParameters();if (ObjectUtils.isEmpty(parameters)) {return EMPTY_ARGS;}//准备args数组,挨个确定每个参数是什么值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) {continue;}//判断解析器是否支持该参数的解析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 ex) {// Leave stack trace for later, exception may actually be resolved and handled...if (logger.isDebugEnabled()) {String exMsg = ex.getMessage();if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {logger.debug(formatArgumentError(parameter, exMsg));}}throw ex;}}//返回所有的参数值return args;}

还有就是请求处理过程中保存在modelAndViewContainer中的临时数据封装到ModelAndView中,返回结果

RequestMappingHandlerAdapter#getModelAndView

 @Nullableprivate ModelAndView getModelAndView(ModelAndViewContainer mavContainer,ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {//模型工厂更新模型数据modelFactory.updateModel(webRequest, mavContainer);if (mavContainer.isRequestHandled()) {return null;}ModelMap model = mavContainer.getModel();//ModelAndViewContainer封装成ModelAndViewModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());if (!mavContainer.isViewReference()) {mav.setView((View) mavContainer.getView());}if (model instanceof RedirectAttributes) {Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);if (request != null) {//重定向数据的共享,RedirectView。先把数据移动到request,再把request移动到session里面RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);}}return mav;}
小结

1、请求处理方法是交给handleAdapter处理的,经过请求校验checkRequest(request)之后,进入invokeHandlerMethod。这里会有一个很强大的类ServletInvocationHandlerMethod,继承了InvocationHandlerMethod和HandlerMethod,组装了各种组件(如HandlerMethodReturnValueHandlerComposite返回值处理器,HandlerMethodArgumentResolverComposite参数解析器)

2、调用ServletInvocationHandlerMethod#invokeAndHandle,来到这个方法,会解析方法参数,执行方法,返回值处理器处理返回值

3、解析方法参数,执行方法由invokeForRequest处理,会ServletInvocationHandlerMethod#getMethodArgumentValues进行参数解析(参数解析),解析完毕进行目标方法的反射执行doInvoke,

4、执行完毕,返回值处理器处理返回值,存放在ModelAndViewContainer

5、getModelAndView得到ModelAndViewContainer中的结果返回

【6】、拦截器后置处理

DispatcherServlet#doDispatch

//【6】拦截器的后置处理
//controller执行完之后,视图渲染之前,执行拦截器的后置处理,可以对modelAndView进行修改
mappedHandler.applyPostHandle(processedRequest, response, mv);

HandlerExecutionChain#applyPostHandle

 void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {//拦截器后置处理,逆序执行for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}}

【7】、处理调度结果

DispatcherServlet#doDispatch

//【7】、异常的处理 和 视图的渲染
//来到这里,请求已经执行完毕,剩下的就是渲染view
//处理结果:包含处理异常,返回ModelAndView
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

这个方法的逻辑,只有两步:异常的处理和视图解析器获取viewName对应的View

DispatcherServlet#processDispatchResult

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);}}//上面所有的解析器都没能处理这个请求,下面直接炸//不存在异常,执行视图渲染// Did the handler return a view to render?//为啥?//因为@ResponseBody,提前在解析返回值的时候,就已经把数据写回去了if (mv != null && !mv.wasCleared()) {//渲染。来解析模型和视图//将viewName转为Viewrender(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 forwardreturn;}if (mappedHandler != null) {// Exception (if any) is already handled..//调用异常处理后的拦截器链mappedHandler.triggerAfterCompletion(request, response, null);}}

异常解析器解析异常,返回异常视图:

DispatcherServlet#processHandlerException

@Nullableprotected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,@Nullable Object handler, Exception ex) throws Exception {// Success and error responses may use different content typesrequest.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);// Check registered HandlerExceptionResolvers...ModelAndView exMv = null;if (this.handlerExceptionResolvers != null) {//所有异常解析器尝试解析异常for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv = resolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}}if (exMv != null) {if (exMv.isEmpty()) {request.setAttribute(EXCEPTION_ATTRIBUTE, ex);return null;}// We might still need view name translation for a plain error model...if (!exMv.hasView()) {String defaultViewName = getDefaultViewName(request);if (defaultViewName != null) {exMv.setViewName(defaultViewName);}}if (logger.isTraceEnabled()) {logger.trace("Using resolved error view: " + exMv, ex);}else if (logger.isDebugEnabled()) {logger.debug("Using resolved error view: " + exMv);}WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());return exMv;}throw ex;}

视图解析器解析视图:

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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale());response.setLocale(locale);//最终渲染解析器解析得到的View视图View view;String viewName = mv.getViewName();if (viewName != null) {// We need to resolve the view name.//解析视图//把目标方法的返回值。(如:index.jsp转为真正能用的View对象)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());}view.render(mv.getModelInternal(), request, response);}catch (Exception ex) {if (logger.isDebugEnabled()) {logger.debug("Error rendering view [" + view + "]", ex);}throw ex;}}

DispatcherServlet#resolveViewName

 //视图解析器解析视图名@Nullableprotected View resolveViewName(String viewName, @Nullable Map<String, Object> model,Locale locale, HttpServletRequest request) throws Exception {if (this.viewResolvers != null) {//拿到所有的视图解析器解析视图名for (ViewResolver viewResolver : this.viewResolvers) {View view = viewResolver.resolveViewName(viewName, locale);if (view != null) {return view;}}}return null;}

请求处理全流程小结

SpringMVC怎么处理客户端的请求?

1、客户端所有的请求,会调用FrameworkServlet#service方法,最终会打到DispatcherServlet上,会调用其doDispatch方法对请求处理,这是SpringMVC请求处理的核心。

2、来到doDispatch

​ ①、上传文件检查,检查该请求是否是上传文件的请求

​ ②、通过getHandler,遍历HandlerMapping获取mapping映射的handler,通过包装成为HandlerExecutionChain,里面存在请求可以处理的方法与拦截器链。(这里涉及到了一个知识点关于@RequestMapping注解的扫描注册)

​ ③、拿到HandlerExecutionChain之后,具体的执行过程是交给HandlerAdapter的,所以还需要获取HandlerAdapter

​ ④、执行拦截器链前置处理。如果返回false,请求直接不处理了,回收资源

​ ⑤、正式处理请求,I、通过ha.handle进入请求处理的逻辑,检查请求session是否携带等问题,检查通过后进行方法的执行。II、执行的过程首先会对HandlerMethod进行包装处理得到ServletInvocationHandlerMethod,这个类很强大,能执行方法,能解析参数,能处理返回值;III、接下来调用ServletInvocationHandlerMethod的invokeAndHandle方法,执行方法需要有参数,ServletInvocationHandlerMethod#getMethodArgumentValues该方法就能够得到方法执行需要的参数,获取参数之后执行doInvoke,得到最终的请求执行结果,通过返回值处理器存放到ModelAndViewContainer中;最终返回的结果从ModelAndViewContainer得取出(这里涉及到了第二个知识点关于@ControllerAdvice注解)

​ ⑥、执行拦截器链后置处理

​ ⑦、异常解析器处理异常,得到异常视图,或者是视图解析器解析视图名得到视图

两个知识点

知识点1:@RequestMapping注解标示的方法的扫描注册是怎么样的?

@RequestMapping注解是在HandlerMapping组件(RequestHandlerMapping)初始化的时候扫描的,调用初始化方法,会扫描所有的@Controller和@RequestMapping注解,建立起mapping和HandlerMethod的映射,存放在mappingRegistry中

知识点2:@ControllerAdvice注解下的方法的扫描缓存是怎么样的?

@ControllerAdvice注解是在HandlerDapter组件(RequestMappingHandlerAdapter)在初始化的时候扫描的,初始化过程中除了创建参数解析器和返回值处理器还调用了initControllerAdviceCache(),能够对@ControllerAdvice注解标示的类进行扫描,得到其底下的异常处理方法,在缓存中建立起bean和method的映射关系

筑基期第一式:SpringMVC源码解析相关推荐

  1. SpringMVC源码解析

     一:springmvc运行过程: 1. dispatcherServlet 通过 HandlerMapping 找到controller 2. controller经过后台逻辑处理得到结果集mode ...

  2. SpringMVC源码解析(四)——请求处理

    2019独角兽企业重金招聘Python工程师标准>>> 前言 这一篇,将着手介绍一次请求的处理.用到了 HandlerMapping.HandlerAdapter 知识,如果遇到不是 ...

  3. SpringMVC源码解析与思考

    首先要知道servletContext与servletConfig servletContext是web应用级别,是jvm进程级别:servletConfig是servlet服务级别,是线程级别. 定 ...

  4. SpringMVC源码解析HandlerMethod

    被 RequestMapping 注解封印的方法模型类. 封装了关于处理器方法信息的方法和bean类 . 提供了对方法参数,方法返回值,方法注释等方便地访问入口. 该类可以使用bean实例或具有bea ...

  5. SpringMVC源码解析之Last-Modified缓存机制

    Spring MVC 支持HTTP协议的 Last-Modified 缓存机制. 支持上次修改的HTTP请求,以方便内容缓存. 相同的合同作为Servlet API中的getLastModified方 ...

  6. SpringMVC源码解析 - HandlerAdapter - HandlerMethodArgumentResolver

    HandlerMethodArgumentResolver主要负责执行handler前参数准备工作. 看个例子,红色部分的id初始化,填充值就是它干的活: 1 @RequestMapping(valu ...

  7. clickhouse原理解析与开发实战 pdf_重识SSM,“超高频面试点+源码解析+实战PDF”,一次性干掉全拿走...

    重识SSM,"超高频面试点"+"源码解析"+"实战PDF",一次性干掉全拿走!! 01 超高频面试点知识篇 1.1 Spring超高频面试点 ...

  8. yolov3之pytorch源码解析_springmvc源码架构解析之view

    说在前面 前期回顾 sharding-jdbc源码解析 更新完毕 spring源码解析 更新完毕 spring-mvc源码解析 更新完毕 spring-tx源码解析 更新完毕 spring-boot源 ...

  9. tns03505 无法解析名称_SpringBootWeb源码解析SpringMVC自动配置

    SpringMVC自动配置 在 Spring Boot 中引入了 spring-boot-starter-web 依赖,并完成了 DispatcherServlet 的自动配置之后,便会通过 WebM ...

最新文章

  1. 生命真的源于宇宙吗?多名宇航员身体,都曾发生“不可逆”的变化
  2. 泡沫破裂之后,强化学习路在何方?
  3. 蓝桥杯第七届决赛真题大全题解(java版本)
  4. [机器学习]回归--(Simple LR and Multiple LR)
  5. rabbitmq-死信队列
  6. Linux内核分析 - 网络[一]:收发数据包的调用
  7. VS2010编译器经常遇到的小问题
  8. hiho一下 第173周
  9. 备考新手指南--QA手册
  10. HashMap之HashMap中hashSeed(hash种子)的作用分析
  11. 批量转移文件,并修改图片的位深度、灰度等信息
  12. MySQL数据库 CPU飙升到100%
  13. 《计算机工程》从投稿到录用之一手经验
  14. 2005年10月--至今 开发过的项目
  15. 6.5编程实例-立方体透视投影
  16. matlab中的代数环问题及其消除方法,Matlab中的代数环问题及其消除方法.pdf
  17. 1343: 平方和与立方和
  18. 谷歌浏览器 刚打开为什么不是设置的主页
  19. MobaXterm 复制粘贴简便方法
  20. 网络监控软件百络网警 v6.6b 企业版 bt

热门文章

  1. 32位(x86)和64位(x64)
  2. 第 8 章 Python 计算生态
  3. html显示已知范围标量,【单选题】下列哪个HTML5元素用于显示已知范围内的标量测量...
  4. 社会工程学工具 SET 伪造网站
  5. CAS Server
  6. 悟空CRM在保险行业的应用
  7. 95文件及文件夹操作实践
  8. 模式识别技术漫谈(5)
  9. ORACLE锁定账户的原因及解决办法
  10. 编程逻辑性思维的重要性