EnableWebMvcConfiguration自动装配类负责加载SpringMVC涉及的HandlerAdapter
、HandlerMapping
、ExceptionHandlerExceptionResolver
等。
SpringMVC利用 DispatchServlet
处理上游Tomcat的请求时,会被HandlerMapping、HandlerAdapter的相关子类分别先后执行,这样做的原因是:
WebMvcAutoConfigurationAdapter自动装配类负责加载SpringMVC涉及的静态资源等Web资源。例如LocaleResolver、视图解析器InternalResourceViewResolver、ContentNegotiatingViewResolver等。
@Configuration(proxyBeanMethods = false)
public class WebMvcAutoConfiguration {
private static final String[] SERVLET_LOCATIONS = { "/" };
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
...
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {...}
...
}
// 该注解保证父类WebMvcConfigurationSupport也参与SpringBoot启动过程中各个注解的解析过程
@Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
...
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager m,
@Qualifier("mvcConversionService") FormattingConversionService c,
@Qualifier("mvcValidator") Validator v) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(m,c, v);
boolean ignoreDefaultModelOnRedirect = this.mvcProperties.isIgnoreDefaultModelOnRedirect();
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || ignoreDefaultModelOnRedirect);
return adapter;
}
...
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager manager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// 调用父类WebMvcConfigurationSupport
return super.requestMappingHandlerMapping(manager, conversionService,resourceUrlProvider);
}
...
}
}
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(...}
@Bean
public PathMatcher mvcPathMatcher() {...}
@Bean
public BeanNameUrlHandlerMapping beanNameHandlerMapping(...}
@Bean
public HandlerExceptionResolver handlerExceptionResolver(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
}
默认生成的众多HandlerMapping子类中,核心包括RequestMappingHandlerMapping
、BeanNameUrlHandlerMapping
、SimpleUrlHandlerMapping
。
HandlerMapping其核心功能是建立RequestUri与目标handler之间的映射关系。
RequestMappingHandlerMapping解析的handler其Uri是被注解@RequestMapping标识的。
BeanNameUrlHandlerMapping解析的Handler其Uri就是该Handler在IOC容器中bean实例对应的beanName。
SimpleUrlHandlerMapping解析的handler其Uri是显式指定的。如下所示:
public SimpleUrlHandlerMapping simpleUrlHandlerMapping(){
SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
Properties properties = new Properties();
// suHm:访问uri,suHmBean:对应的控制器bean
properties.setProperty("suHm","suHmBean");
simpleUrlHandlerMapping.setMappings(properties);
simpleUrlHandlerMapping.setOrder(1);
return simpleUrlHandlerMapping;
}
BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping的异同:
类HandlerAdapter负责触发目标类目标方法的执行。
BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping对应的HandlerAdapter为SimpleControllerHandlerAdapter。
RequestMappingHandlerAdapter、SimpleControllerHandlerAdapter
是常见的HandlerAdapter,其中SimpleControllerHandlerAdapter负责处理实现接口Controller的handler。
具体参考文章
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response){
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);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
...
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
...
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 执行目标类的目标方法,即有可能返回ModelAndView,也可能只有HttpServletResponse。其实ModelAndView是执行完目标方法
//进一步渲染视图,渲染后的视图最终还是通过HttpServletResponse响应到客户端。如果没有视图则ModelAndView为null,最终目标
//方法的返回值被对应handler写到HttpServletResponse并响应到客户端。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如果存在ModelAndView 则渲染视图,否则直接忽略
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}...
//渲染目标方法返回结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
mappedHandler.triggerAfterCompletion(request, response, ex);
}
...
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler,ModelAndView mv,Exception exception) {
boolean errorView = false;
if (mv != null && !mv.wasCleared()) {
// 这种情况主要是对视图View的渲染
render(mv, request, response);
...
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
}
对于SimpleControllerHandlerAdapter,其目标方法即为接口Controller的抽象方法,在子类重写其方法内部最终返回值为ModelAndView类型以及HttpServletResponse。如果最终结果存在视图渲染则ModelAndView类型是视图相关内容,最终将HttpServletResponse内部响应结果渲染至ModelAndView代表的视图中。
public class DispatcherServlet extends FrameworkServlet {
private List<HandlerMapping> handlerMappings;
private List<HandlerExceptionResolver> handlerExceptionResolvers;
private List<HandlerAdapter> handlerAdapters;
@Override//Tomcat处理请求过程中触发
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
//handlerMappings中添加所有元素:从IOC容器中获取HandlerMapping接口的全部相关子类。
initHandlerMappings(context);
//HandleAdapter中添加所有元素:从IOC容器中获取HandleAdapter接口的全部相关子类。
initHandlerAdapters(context);
//同理...
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
Servlet容器之Tomcat处理请求过程中触发 初始化SpringMVC九大组件 的流程。此时DispatcherServlet类中集合类型的属性之handlerMappings & handlerExceptionResolvers & handlerAdapters中元素均为SpringBoot自动装配类组件,截止当前所有组件已经初始化完毕,只需从IOC容器获取相关类型的组件即可。目的是用于处理客户端请求,由此得知该集合类型赋值过程有且仅有一次,即处理首次客户端请求。
着重关注三种类型之RequestMappingHandlerMapping
、BeanNameUrlHandlerMapping
、SimpleUrlHandlerMapping
的执行流程。
public class DispatcherServlet extends FrameworkServlet {
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
}
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping{
public final HandlerExecutionChain getHandler(HttpServletRequest request) {
// 通过requestUri获取对应的handler
Object handler = getHandlerInternal(request);
...
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
...
return executionChain;
}
}
其中,RequestMappingHandlerMapping得到的handler类型为HandlerMethod【对目标方法的抽象化】
,在HandlerMethod内部维护元素:目标handler的真实类型 以及 目标方法Method
。
public class RequestMappingHandlerMapping{
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request){
// AbstractHandlerMethodMapping#getHandlerInternal
return super.getHandlerInternal(request);
}
}
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
}
BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping 该俩HandlerMapping通过requestUri获取得到的handler为接口Controller类型的没有做任何抽象的实际handler。
RequestMappingHandlerAdapter、SimpleControllerHandlerAdapter
是常见的HandlerAdapter。
通过如下方法返回符合当前请求的HandlerAdapter。
public class DispatcherServlet extends FrameworkServlet {
protected HandlerAdapter getHandlerAdapter(Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
}
}
由其抽象类AbstractHandlerMethodAdapter完成目标HandlerAdapter的鉴定条件。
public abstract class AbstractHandlerMethodAdapter{
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
}
符合处理BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping的HandlerAdapter两种类型的HandlerAdapter即为当前的SimpleControllerHandlerAdapter。因为两者HandlerMapping对应目标handler都是直接实现Controller接口。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
}
着重分析RequestMappingHandlerAdapter以及SimpleControllerHandlerAdapter。
public abstract class AbstractHandlerMethodAdapter{
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod){
...
return invokeHandlerMethod(request, response, handlerMethod);;
}
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
...
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//设置目标方法所有参数的抽象体
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
//设置目标方法返回值的抽象体
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
...
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
}
}
}
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
public void invokeAndHandle(ServletWebRequest wr,ModelAndViewContainer mc,Object... args){
// 调用目标方法得到的实际返回值
Object returnValue = invokeForRequest(webRequest, mc, args);
if(returnValue == null)return;
MethodParameter mp = getReturnValueType(returnValue);
// 处理返回值
this.returnValueHandlers.handleReturnValue(returnValue, mp, mc, wr);
}
}
BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping 两者对应的实际handler都是直接实现接口Controller。所以对于上述两种HandlerMapping,当前HandlerAdapter执行两者目标类的目标方法其实都是重写接口Controller的方法handleRequest。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 直接调用目标类的目标方法
return ((Controller) handler).handleRequest(request, response);
}
}
本章节不分析SpringMVC渲染视图等结果行为,只分析RequestMappingHandlerMapping对应的响应结果。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
public void afterPropertiesSet() {
// 注意与全部异常拦截的区别
initControllerAdviceCache();
...
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
// 一共提供了15种类型
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
}
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
//returnValueHandlers元素:支持返回值类型为15种
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
public HandlerMethodReturnValueHandlerComposite addHandlers(
List<? extends HandlerMethodReturnValueHandler> handlers) {
if (handlers != null) {
this.returnValueHandlers.addAll(handlers);
}
return this;
}
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//将 handler实际返回值returnValue 包装为 ReturnValueMethodParameter类型
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
@Nullable
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
// 本文着重分析handler之RequestResponseBodyMethodProcessor
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
}
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
//目标类注解中是否存在ResponseBody注解
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
// 目标方法是否存在ResponseBody注解
returnType.hasMethodAnnotation(ResponseBody.class));
}
@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);
// 最后通过响应头的响应类型返回,否则根据目标方法实际返回值类型返回
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}