简述 由于现在基本使用的都是 SpringBoot
项目来启动,所以我就直接建立在 SpringBoot
基础下看 WEB
容器了。 如果有一些项目开发经验就知道,SpringWEB
模块又名 SpringMVC
,提供了视图数据整合以及可以直接返回 JSON
数据。前几年 JSP
当道的时候,各种 ViewResolver
层出不穷,据我所知的就有 FreeMarker
JSP
Beetl
等等。不过最近几年前端发生爆炸性变化,前后端能分离的都分离了,需要 SEO
的也很少使用 Java
来做了。所以现在 Java
后端项目的主要责职是提供业务所需要的交互数据给前端,不仅仅使用 JSON
,还可以整合其他的传输协议,比如 Hessian
XML
Protobuf
等等,只要够折腾,什么格式都可以返回,不想折腾就使用 JSON
就可以了。 数据转换模块也会被 Spring
独立出来这个自然不需要再猜测,所以我们也可以为了减少传输使用的宽带,去定义第几个字节是什么东西。 那我们现在可以直接进入 SpringMVC
的源码来看看了。
初始化Web环境 在 JavaWEB
中,如果需要提供网络服务,一般是实现 Servlet
对象,像 Tomcat
Resign
等网络容器都提供了自己的实现,我们就简单的用常用的 Tomcat
来说,Tomcat
会拿到我们项目中所有的 HTTPServlet
然后根据不同的 HTTP Method
HTTP URL
来调用不同的 Servlet
方法来完成请求。 那 SpringMVC
是在 Servlet
级别的,所以这个容器必定会存在,那就是 DispatcherServlet
。简单的理解 DispatcherServlet
就是一个在项目启动时读取 了所有请求处理器,然后有请求进来根据不同的定义来调用不同的请求处理器 的一个 Servlet
容器。 把断点打在 DispatcherServlet
的无参构造器上,找到初始化入口,是在 refreshContext(context)
中进行的,那我们就从这里开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public ConfigurableApplicationContext run (String... args) { StopWatch stopWatch = new StopWatch (); stopWatch.start(); ConfigurableApplicationContext context = null ; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList <>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments (args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class [] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this .logStartupInfo) { new StartupInfoLogger (this .mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException (ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null ); throw new IllegalStateException (ex); } return context; }
一系列之前说过的步骤以后,来到这里:
1 2 3 4 protected void refresh (ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
之前说过,调用 refresh
是个模板方法,AbstractApplicationContext
的 refresh
是个模板方法,会调用子类实现的 onRefresh
。因为当前是个 WEB
项目,所以实现类 AnnotationConfigServletWebServerApplicationContext
的 onRefresh
提供了实现:
1 2 3 4 5 6 7 8 9 10 @Override protected void onRefresh () { super .onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException ("Unable to start web server" , ex); } }
第一件事请 super.onRefresh()
是调用父级 GenericWebApplicationContext
的函数,不过这段函数现在看来应该没什么多大的用处了:
1 2 3 4 5 6 7 @Override protected void onRefresh () { this .themeSource = UiApplicationContextUtils.initThemeSource(this ); }
是一个初始化界面主题的函数,一开始我还怀疑这个主题是不是什么主题,然而进入 UiApplicationContextUtils.initThemeSource
看的时候,还真的就是 HTML
主题,里面定义了从哪里读取 CSS
呀这些鬼东西,跳过不看。 重点来看看 createWebServer()
做了哪些事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private void createWebServer () { WebServer webServer = this .webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null ) { ServletWebServerFactory factory = getWebServerFactory(); this .webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null ) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException ("Cannot initialize servlet context" , ex); } } initPropertySources(); }
这时候获取了一个 ServletWebServerFactory
的 BeanDefinition
,然后使用这个 Factory
来创建我们目前的 Web
环境。
1 2 3 4 5 6 7 8 9 10 11 12 13 protected ServletWebServerFactory getWebServerFactory () { String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0 ) { throw new ApplicationContextException ("Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean." ); } if (beanNames.length > 1 ) { throw new ApplicationContextException ("Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0 ], ServletWebServerFactory.class); }
内置Tomcat注入 然而这个ServletWebServerFactory
什么时候偷偷被放进去的,我们现在快速过一遍:
SpringBoot
启动的时候,在构造器调用了元信息读取器,读取了 META-INF/spring.factories
中配置的工厂,后初始化的时候会用到这些配置的类;
SpringBoot
中上面的配置文件配置了这个工厂:ServletWebServerFactoryAutoConfiguration
看这个工厂有什么信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @ConditionalOnClass(ServletRequest.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration { @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer (ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer (serverProperties); } @Bean @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat") public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer ( ServerProperties serverProperties) { return new TomcatServletWebServerFactoryCustomizer (serverProperties); } }
然后我们看到上面导入那里导入了内置 Tomcat
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Configuration(proxyBeanMethods = false) class ServletWebServerFactoryConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedTomcat { @Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory ( ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory (); factory.getTomcatConnectorCustomizers() .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatContextCustomizers() .addAll(contextCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatProtocolHandlerCustomizers() .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList())); return factory; } } }
所以这个 ServletWebServerFactory
就在读取配置的时候被自动导入到 BeanDefinitionMaps
中去。
DispatcherServlet构建 怎么会涉及这一块的初始化呢,是因为上面 ServletWebServerFactoryConfiguration
初始化完成以后,触发的 ServletWebServerFactoryConfiguration
初始化,先来看看 ServletWebServerFactoryConfiguration
的注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet" ; public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration" ; @Configuration(proxyBeanMethods = false) @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class }) protected static class DispatcherServletConfiguration { @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet (HttpProperties httpProperties, WebMvcProperties webMvcProperties) { DispatcherServlet dispatcherServlet = new DispatcherServlet (); dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents()); dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails()); return dispatcherServlet; } @Bean @ConditionalOnBean(MultipartResolver.class) @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) public MultipartResolver multipartResolver (MultipartResolver resolver) { return resolver; } } }
这个初始化就很有灵性了,跟我们平常写的配置类大致一致。那关于 DispatcherServlet
的配置,我们均可以通过配置 WebMvcProperties
来让他注入到当前的 DispatcherServlet
。 这就完了😱?映射呢映射呢? 好吧,差点忘记此时 HTTPServlet
还没有初始化。
DispatcherServlet初始化(一) 默认的 HTTPServlet
在启动的时候只有装载,并没有初始化,初始化发生在第一次请求的时候。 我们来看看这个类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable , EnvironmentAware { @Override public final void init () throws ServletException { 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; } } initServletBean(); } }
FrameworkServlet
实现上面的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 @Override protected 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 { 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" ); } } 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(); } if (wac == null ) { wac = createWebApplicationContext(rootContext); } if (!this .refreshEventReceived) { synchronized (this .onRefreshMonitor) { onRefresh(wac); } } if (this .publishContext) { String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); } return wac; }
刷新上下文在上面那么多个容器中已经很有感觉了,就是刷新配置的 Bean
调用对应的构造器 AOP
注入啊啊巴拉巴拉。 所以,onRefresh
是整个 Web
容器初始化的关键:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 DispatcherServlet.java: @Override protected void onRefresh (ApplicationContext context) { initStrategies(context); } protected void initStrategies (ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
我大概只对 initHandlerMappings
和 initHandlerAdapters
感兴趣。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 private void initHandlerMappings (ApplicationContext context) { this .handlerMappings = null ; if (this .detectAllHandlerMappings) { Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true , false ); if (!matchingBeans.isEmpty()) { this .handlerMappings = new ArrayList <>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this .handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this .handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { } } 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" ); } } }
那么这些 handlerMappings
是什么时候被装配的,通过 WebMvcAutoConfiguration
这个配置类自动装配的,并且装配发生在 DispatcherServletAutoConfiguration
之后。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { @Override protected RequestMappingHandlerMapping createRequestMappingHandlerMapping () { if (this .mvcRegistrations != null && this .mvcRegistrations.getRequestMappingHandlerMapping() != null ) { return this .mvcRegistrations.getRequestMappingHandlerMapping(); } return super .createRequestMappingHandlerMapping(); } }
RequestMappingHandlerMapping装配 上面我们看到,RequestMappingHandler
是通过自动装配的形式放入 BeanFactory
的,那至于我们编写的 @Controller
以及 @RestController
是怎么被读取的,就是通过装配时,调用 InitializingBean
接口的 afterPropertiesSet
方法进行装配的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Override public void afterPropertiesSet () { this .config = new RequestMappingInfo .BuilderConfiguration(); this .config.setUrlPathHelper(getUrlPathHelper()); this .config.setPathMatcher(getPathMatcher()); this .config.setSuffixPatternMatch(this .useSuffixPatternMatch); this .config.setTrailingSlashMatch(this .useTrailingSlashMatch); this .config.setRegisteredSuffixPatternMatch(this .useRegisteredSuffixPatternMatch); this .config.setContentNegotiationManager(getContentNegotiationManager()); super .afterPropertiesSet(); } @Override public void afterPropertiesSet () { initHandlerMethods(); } protected void initHandlerMethods () { for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }
拿到 BeanFactory
中所有的 Bean
一顿循环😶:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected void processCandidateBean (String beanName) { Class<?> beanType = null ; try { beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'" , ex); } } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } }
当 Bean
有 @Controller
或者 @RequestMapping
就判定是一个控制器:
1 2 3 4 5 6 @Override protected boolean isHandler (Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
注册处理器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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); }); } }
接下来我们看注册控制器,Spring
又定义了一个 Mapping
容器,用于注册 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Override protected void registerHandlerMethod (Object handler, Method method, RequestMappingInfo mapping) { super .registerHandlerMethod(handler, method, mapping); updateConsumesCondition(mapping, method); } protected void registerHandlerMethod (Object handler, Method method, T mapping) { this .mappingRegistry.register(mapping, handler, method); } class MappingRegistry { private final Map<T, MappingRegistration<T>> registry = new HashMap <>(); private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap <>(); private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap <>(); private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap <>(); private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap <>(); private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock (); }
DispatcherServlet装配(二) 好了,在上面的装配中插入了 RequestMappingHandlerMapping
的装配,现在回来继续看两个方法:initHandlerMappings
和 initHandlerAdapters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 private void initHandlerMappings (ApplicationContext context) { this .handlerMappings = null ; if (this .detectAllHandlerMappings) { Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true , false ); if (!matchingBeans.isEmpty()) { this .handlerMappings = new ArrayList <>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this .handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this .handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { } } 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" ); } } }
initHandlerAdapters
也差不多代码就不贴上来了。
处理HTTP请求准备 那 HTTPServlet
处理请求是在 service
方法中处理的,所以现在我们需要先进入核心的这个方法中去看: FrameworkServlet
即这个 HTTPServlet
的第一个实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @Override protected final void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } @Override protected final void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } @Override protected final void doPut (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } @Override protected final void doDelete (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
那么其实在 FrameworkServlet
中,每一个 doXXX
都是交给 processRequest(request, response);
来做处理,所以现在我们主要看这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 protected final void processRequest (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null ; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); 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); } }
查找控制器进行处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 protected void doService (HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); Map<String, Object> attributesSnapshot = null ; if (WebUtils.isIncludeRequest(request)) { 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 { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { if (attributesSnapshot != null ) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } }
doDispatch
就是查找控制器,并且整合拦截器调用的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 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 = getHandler(processedRequest); if (mappedHandler == null ) { noHandlerFound(processedRequest, response); return ; } 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 ; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return ; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return ; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException ("Handler dispatch failed" , err); } 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 { if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
目前的拦截器链有四个:
RequestMappingHandlerAdapter
;
HandlerFunctionAdapter
;
HttpRequestHandlerAdapter
;
SimpleControllerHandlerAdapter
在查找的过程中,返回第一个匹配的适配器:
1 2 3 4 5 6 7 8 9 10 11 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" ); }
那么我们现在拿到的实例就是 RequestMappingHandlerAdapter
: 然后看看调用 mv = ha.handle(processedRequest, response, mappedHandler.getHandler())
做什么什么事情:
1 2 3 4 5 6 7 @Override @Nullable public final ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Override protected ModelAndView handleInternal (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(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); } } return mav; }
构建请求处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 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(); } }
ServletInvocableHandlerMethod处理请求调用 拿到调用的 ServletWebRequest
以及 ModelAndViewContainer
开始处理请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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; } }
转换请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Nullable 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); } protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_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) { if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
通过反射调用控制器方法执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Nullable protected Object doInvoke (Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try { return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument" ); throw new IllegalStateException (formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException (formatInvokeError("Invocation failure" , args), targetException); } } }
HandlerMethodReturnValueHandlerComposite处理返回值写出 循环所有消息处理器,拿到第一个支持的 HandlerMethodReturnValueHandler
调用处理器将结果写出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Override 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); } @Nullable 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 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override 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); writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
获取返回值,根据 HTTPHeaders
进行匹配转换器,转换写入 Response
流中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 protected <T> void writeWithMessageConverters (@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Object body; Class<?> valueType; Type targetType; if (value instanceof CharSequence) { body = value.toString(); valueType = String.class; targetType = String.class; } else { body = value; valueType = getReturnValueType(body, returnType); targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass()); } if (isResourceType(value, returnType)) { outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes" ); if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null && outputMessage.getServletResponse().getStatus() == 200 ) { Resource resource = (Resource) value; try { List<HttpRange> httpRanges = inputMessage.getHeaders().getRange(); outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value()); body = HttpRange.toResourceRegions(httpRanges, resource); valueType = body.getClass(); targetType = RESOURCE_REGION_LIST_TYPE; } catch (IllegalArgumentException ex) { outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength()); outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value()); } } } MediaType selectedMediaType = null ; MediaType contentType = outputMessage.getHeaders().getContentType(); boolean isContentTypePreset = contentType != null && contentType.isConcrete(); if (isContentTypePreset) { if (logger.isDebugEnabled()) { logger.debug("Found 'Content-Type:" + contentType + "' in response" ); } selectedMediaType = contentType; } else { HttpServletRequest request = inputMessage.getServletRequest(); List<MediaType> acceptableTypes = getAcceptableMediaTypes(request); List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType); if (body != null && producibleTypes.isEmpty()) { throw new HttpMessageNotWritableException ( "No converter found for return value of type: " + valueType); } List<MediaType> mediaTypesToUse = new ArrayList <>(); for (MediaType requestedType : acceptableTypes) { for (MediaType producibleType : producibleTypes) { if (requestedType.isCompatibleWith(producibleType)) { mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType)); } } } if (mediaTypesToUse.isEmpty()) { if (body != null ) { throw new HttpMediaTypeNotAcceptableException (producibleTypes); } if (logger.isDebugEnabled()) { logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes); } return ; } MediaType.sortBySpecificityAndQuality(mediaTypesToUse); for (MediaType mediaType : mediaTypesToUse) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break ; } else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break ; } } if (logger.isDebugEnabled()) { logger.debug("Using '" + selectedMediaType + "', given " + acceptableTypes + " and supported " + producibleTypes); } } if (selectedMediaType != null ) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> converter : this .messageConverters) { GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null ); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter <?>>) converter.getClass(), inputMessage, outputMessage); 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); } } else { if (logger.isDebugEnabled()) { logger.debug("Nothing to write: null body" ); } } return ; } } } if (body != null ) { if (isContentTypePreset) { throw new HttpMessageNotWritableException ( "No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'" ); } throw new HttpMediaTypeNotAcceptableException (this .allSupportedMediaTypes); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Override public final void write (final T t, @Nullable final Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { final HttpHeaders headers = outputMessage.getHeaders(); addDefaultHeaders(headers, t, contentType); if (outputMessage instanceof StreamingHttpOutputMessage) { StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage; streamingOutputMessage.setBody(outputStream -> writeInternal(t, type, new HttpOutputMessage () { @Override public OutputStream getBody () { return outputStream; } @Override public HttpHeaders getHeaders () { return headers; } })); } else { writeInternal(t, type, outputMessage); outputMessage.getBody().flush(); } }
使用 JSON
流的形式写出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 @Override protected void writeInternal (Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { MediaType contentType = outputMessage.getHeaders().getContentType(); JsonEncoding encoding = getJsonEncoding(contentType); JsonGenerator generator = this .objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding); try { writePrefix(generator, object); Object value = object; Class<?> serializationView = null ; FilterProvider filters = null ; JavaType javaType = null ; if (object instanceof MappingJacksonValue) { MappingJacksonValue container = (MappingJacksonValue) object; value = container.getValue(); serializationView = container.getSerializationView(); filters = container.getFilters(); } if (type != null && TypeUtils.isAssignable(type, value.getClass())) { javaType = getJavaType(type, null ); } ObjectWriter objectWriter = (serializationView != null ? this .objectMapper.writerWithView(serializationView) : this .objectMapper.writer()); if (filters != null ) { objectWriter = objectWriter.with(filters); } if (javaType != null && javaType.isContainerType()) { objectWriter = objectWriter.forType(javaType); } SerializationConfig config = objectWriter.getConfig(); if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) && config.isEnabled(SerializationFeature.INDENT_OUTPUT)) { objectWriter = objectWriter.with(this .ssePrettyPrinter); } objectWriter.writeValue(generator, value); writeSuffix(generator, object); generator.flush(); } catch (InvalidDefinitionException ex) { throw new HttpMessageConversionException ("Type definition error: " + ex.getType(), ex); } catch (JsonProcessingException ex) { throw new HttpMessageNotWritableException ("Could not write JSON: " + ex.getOriginalMessage(), ex); } }
doDispatch直接其他善后操作 1 2 3 4 5 6 7 8 9 10 11 12 13 protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception { mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return ; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); }
后面的工作就是轮询拦截器执行后处理的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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); } } }
完