DispatcherServlet
源码结构DispatcherServlet
类中doDispatch()
方法其中最重要的两个方法是ha.handle()
执行目标方法,processDispatchResult()
转发到页面
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
//1、checkMultipart(request)检查是否是文件上传请求
processedRequest = this.checkMultipart(request);
//如果是文件上传请求,那么request包装成了processedRequest,就不等于了原来的request请求,用变量multipartRequestParsed 记录了是否是文件上传请求
multipartRequestParsed = processedRequest != request;
//2、根据当前请求确定使用哪个处理器
mappedHandler = this.getHandler(processedRequest);
//3、如果没有找到哪个处理器能处理这个请求就404或者抛出异常
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//4、拿到能执行这个处理器类的所有方法的适配器(反射工具)
HandlerAdapter ha = this.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;
}
//5、Controller处理器的方法被调用,通过前面拿到的ha适配器来执行相应的目标方法,并将目标方法返回值作为试图名,设置保存到ModelAndView中
//目标无法无论返回什么,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView返回
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果目标方法返回值是void,那么就会设置一个默认的试图名
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//6、转发到目标页面。根据方法最终执行完成封装的ModelAndView,转发到对应页面,而且ModelAndView中的数据可以从请求域中获取
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
请求的流程:
1、所有请求过来DispatcherServlet
收到请求
2、调用doDispatch()
方法处理请求
getHandler()
方法,根据当前请求地址找到能处理这个请求的目标处理器类(控制器)HandlerMapping
中找到这个请求的映射信息,获取到目标处理器类getHandlerAdapter()
方法,根据当前处理器类获取到能执行这个处理器方法的适配器HandlerAdapter
(适配器)AnnotationMethodHandlerAdapter
)执行目标方法ModelAndView
对象并返回ModelAndView
的信息转发到具体的页面,并可以在请求域中取出ModelAndView
中模型数据getHandler()
方法此方法根据当前请求能够找到哪个类可以处理该请求,方法会返回目标处理器类的执行链
IOC容器启动创建Controller
对象的时候扫描每个处理器都能处理什么请求,保存在HandlerMapping
的handlerMap
属性中,等下一次请求过来的时候,就来看哪个HandlerMapping
中有这个请求映射信息就可以了。
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//handlerMapping:处理器映射,里面保存了每一个处理器能够处理哪些请求的映射信息
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
getHandlerAdapter()
方法此方法可以找到目标处理器类的适配器,只有得到适配器才能执行目标方法。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
//判断循环中当前的适配器是否支持目标处理器类
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");
}
HttpRequestHandlerAdapter
public boolean supports(Object handler) {
//判断当前的处理器是否实现了HttpRequestHandler这个接口
return (handler instanceof HttpRequestHandler);
}
SimpleControllerHandlerAdapter
@Override
public boolean supports(Object handler) {
//判断当前的处理器是否实现了Controller这个接口
return (handler instanceof Controller);
}
AbstractHandlerMethodAdapter
其中包含了可以解析注解方法的适配器,处理器类中只要标注了注解的这些方法就能用
public final boolean supports(Object handler) {
//
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
ha.handle()
方法此方法用来确定目标方法并执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
执行目标方法后,返回ModelAndView
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
调用invokeHandlerMethod()
方法
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//将HttpServletRequest 包装成ServletWebRequest
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();
}
}
真正执行目标方法的代码,目标方法利用反射执行期间确定参数值,提前执行modelAttribute
等所有的操作都在这个方法中。
invocableMethod.invokeAndHandle(webRequest, mavContainer);
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
//创建和参数长度一样长的数组
Object[] args = new Object[parameters.length];
//通过循环得到每一个参数的信息
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (this.logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
this.logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
对于有注解的参数,保存参数是哪个注解的详细信息,如果参数有ModelAttribute
注解,就会拿到这个注解的值让attrName
保存。
对于没有注解的参数,首先看是否是普通参数(即是否是原生API);再看是否是Model
或者Map
;如果是就传入隐含模型保存。如果不是普通参数而是自定义类型的参数,如果没ModelAttribute
注解,就会先看是否是原生API;再看是否是Model
或者Map
;再看是否是其它类型,如SessionStatus
、HttpEntity
、Errors
类型;都不是最后再看是否是简单类型属性,如Integer
、String
等,会给paramName
赋值。如果所有类型都不是则attrName=""
。如果是自定义类型的对象,最终会产生两个效果,即如果这个参数标注了ModelAttribute
注解就会给attrName
赋值为这个注解的value
值;如果这个参数没有标注ModelAttribute
注解就会给attName
赋值为""
。
SpringMVC确定POJO的值分为三步:
ModelAttribute
注解),则POJO就是注解指定的value,没有标注解就是参数类型的首字母小写指定的值。如果有将这个值赋值给bindObject
。DispatcherServlet
类中有九个引用类型的属性,称为SpringMVC九大组件,SpringMVC在工作的时候,关键位置都是由这些组件来完成的。
九大组件都是接口,接口就是规范,提供了非常强大的扩展性。SpringMVC核心就是九大组件的工作原理。
/** MultipartResolver used by this servlet. */
@Nullable
private MultipartResolver multipartResolver; //文件上传解析器
/** LocaleResolver used by this servlet. */
@Nullable
private LocaleResolver localeResolver; //区域信息解析器,和国际化有关
/** ThemeResolver used by this servlet. */
@Nullable
private ThemeResolver themeResolver; //主题解析器,强大的主题效果更换
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings; //Handler映射信息
/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters; //Handler的适配器
/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers; //SpringMVC异常解析器
/** RequestToViewNameTranslator used by this servlet. */
@Nullable
private RequestToViewNameTranslator viewNameTranslator; //目标方法没有返回值,则把请求地址作为试图名,试图名转换器
/** FlashMapManager used by this servlet. */
@Nullable
private FlashMapManager flashMapManager; //FlashMap管理器,管理SpringMVC中运行重定向携带数据
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers; //试图解析器
九大组件初始化
服务器一启动就执行初始化方法
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);
}
HandlerMapping
初始化
/**
* Initialize the HandlerMappings used by this class.
* If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
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");
}
}
}
组件的初始化是去容器中找这个组件,如果没有找到就使用默认的配置,有些组件在容器中是使用类型找的,有些组件是使用id找的。