dispatchServlet大概流程结构图
以下是其方法
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);
// Determine handler for the current request.
//找哪个handler处理器即扫描的controller放行
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
// 如果没找到请求就转到错误页面
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//根据controller找适配器handler 就requestMapping映射
//反射工具annotationMethodHandlerAdpater
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
//请求方式
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//适配器handler调用,执行目标方法,返回的都封装在modelAndView中
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//这个是来到页面的方法
//将modelAndView方法封装转发到对应的页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
1.具体流程页面请求到dispatcherServlet调用dodispatch方法
2.gethandler:根据页面请求地址寻找controller处理类
3.gethandlerAdapter找到处理这个处理器方法的适配类
4.使用刚才的获取到的适配器(AnotationMethodAdapter)执行目标方法
5.目标方法执行后会返回一个ModelAndView对象
6.根据modelAndView所携带的信息返回到页面,可以从域中获取携带的信息。
探究 mappedHandler = getHandler(processedRequest);(获取的是handler执行链)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//handlerMappings标注哪个处理器能处理哪个请求
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
handlerMapping里面存着beanNameUrlHandlerMapping里面是框架配置的
DefaultHandlerAnotaionHandlerMapping这是注解的,依次扫描
接着从 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());中找适配器的方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
//可以遍历出AnnotationMethodHandlerAdapter
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
DispatcherServlet中有九个引用类型称为 ,springMVC九大组件,全部是接口。接口就是规范,提供的类不够用就自己提供
//文件上传请求
private MultipartResolver multipartResolver;
//国际化
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;
//主题解析
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;
//
/** List of HandlerMappings used by this servlet */
private List handlerMappings;
//handler适配器
/** List of HandlerAdapters used by this servlet */
private List handlerAdapters;
//处理器异常解析器
/** List of HandlerExceptionResolvers used by this servlet */
private List handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet */
private FlashMapManager flashMapManager;
//视图解析器
/** List of ViewResolvers used by this servlet */
private List 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);
}
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
// We keep HandlerMappings in sorted order.
OrderComparator.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.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这一步进入查看
来到AnotationMethodHandlerAdapter下的
return invokeHandlerMethod(request, response, handler);方法
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//获取方法解析器
ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
//根据请求获取处理的方法
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
//方法执行器
ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
//原生的进行包装
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//new一个隐含模型bingawareModleMap
ExtendedModelMap implicitModel = new BindingAwareModelMap();
//下面是真正执行的目标方法
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
ModelAndView mav =
methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
return mav;
}
进入Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);方法
public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
try {
boolean debug = logger.isDebugEnabled();
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
if (attrValue != null) {
implicitModel.addAttribute(attrName, attrValue);
}
}
//找AttributeMethod注解的方法
for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
//确定ModelAttributeMethod执行的参数的值
Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
if (debug) {
logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
}
String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
continue;
}
ReflectionUtils.makeAccessible(attributeMethodToInvoke);
//提前运行所有的modelAttribute方法
Object attrValue = attributeMethodToInvoke.invoke(handler, args);
if ("".equals(attrName)) {
//判断modelAttribute上是否有value值
Class> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
}
if (!implicitModel.containsAttribute(attrName)) {
implicitModel.addAttribute(attrName, attrValue);
}
}
//再次解析目标方法的参数,之前是解析modelAtrribute现在是目标的方法继续进入下方方法
Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
if (debug) {
logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
}
ReflectionUtils.makeAccessible(handlerMethodToInvoke);
return handlerMethodToInvoke.invoke(handler, args);
}
catch (IllegalStateException ex) {
// Internal assertion failed (e.g. invalid signature):
// throw exception with full handler method context...
throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
}
catch (InvocationTargetException ex) {
// User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
ReflectionUtils.rethrowException(ex.getTargetException());
return null;
}
}
resolveHandlerArguments进入确定参数
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
Class>[] paramTypes = handlerMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length];
for (int i = 0; i < args.length; i++) {
MethodParameter methodParam = new MethodParameter(handlerMethod, i);
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
String paramName = null;
String headerName = null;
boolean requestBodyFound = false;
String cookieName = null;
String pathVarName = null;
String attrName = null;
boolean required = false;
String defaultValue = null;
boolean validate = false;
Object[] validationHints = null;
int annotationsFound = 0;
Annotation[] paramAnns = methodParam.getParameterAnnotations();
//如果有注解就解析,并保存注解信息
for (Annotation paramAnn : paramAnns) {
if (RequestParam.class.isInstance(paramAnn)) {
RequestParam requestParam = (RequestParam) paramAnn;
paramName = requestParam.value();
required = requestParam.required();
defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
annotationsFound++;
}
else if (RequestHeader.class.isInstance(paramAnn)) {
RequestHeader requestHeader = (RequestHeader) paramAnn;
headerName = requestHeader.value();
required = requestHeader.required();
defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
annotationsFound++;
}
else if (RequestBody.class.isInstance(paramAnn)) {
requestBodyFound = true;
annotationsFound++;
}
else if (CookieValue.class.isInstance(paramAnn)) {
CookieValue cookieValue = (CookieValue) paramAnn;
cookieName = cookieValue.value();
required = cookieValue.required();
defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
annotationsFound++;
}
else if (PathVariable.class.isInstance(paramAnn)) {
PathVariable pathVar = (PathVariable) paramAnn;
pathVarName = pathVar.value();
annotationsFound++;
}
else if (ModelAttribute.class.isInstance(paramAnn)) {
ModelAttribute attr = (ModelAttribute) paramAnn;
attrName = attr.value();
annotationsFound++;
}
else if (Value.class.isInstance(paramAnn)) {
defaultValue = ((Value) paramAnn).value();
}
else {
Validated validatedAnn = AnnotationUtils.getAnnotation(paramAnn, Validated.class);
if (validatedAnn != null || paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
validate = true;
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(paramAnn));
validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
}
}
}
if (annotationsFound > 1) {
throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
"do not specify more than one such annotation on the same parameter: " + handlerMethod);
}
//没找到注解的情况下
if (annotationsFound == 0) {
//这个进去看看看是否是原生API
//
Object argValue = resolveCommonArgument(methodParam, webRequest);
if (argValue != WebArgumentResolver.UNRESOLVED) {
args[i] = argValue;
}
else if (defaultValue != null) {
args[i] = resolveDefaultValue(defaultValue);
}
else {
Class> paramType = methodParam.getParameterType();
if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
if (!paramType.isAssignableFrom(implicitModel.getClass())) {
throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
"Model or Map but is not assignable from the actual model. You may need to switch " +
"newer MVC infrastructure classes to use this argument.");
}
//将隐藏Model赋值给参数Model,args获得model再返回上面方法
args[i] = implicitModel;
}
else if (SessionStatus.class.isAssignableFrom(paramType)) {
args[i] = this.sessionStatus;
}
else if (HttpEntity.class.isAssignableFrom(paramType)) {
args[i] = resolveHttpEntityRequest(methodParam, webRequest);
}
else if (Errors.class.isAssignableFrom(paramType)) {
throw new IllegalStateException("Errors/BindingResult argument declared " +
"without preceding model attribute. Check your handler method signature!");
}
else if (BeanUtils.isSimpleProperty(paramType)) {
paramName = "";
}
else {
attrName = "";
}
}
}
// 确定值的环节
if (paramName != null) {
args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
}
else if (headerName != null) {
args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
}
else if (requestBodyFound) {
args[i] = resolveRequestBody(methodParam, webRequest, handler);
}
else if (cookieName != null) {
args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
}
else if (pathVarName != null) {
args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
}
//这是确定自定义类型的参数
else if (attrName != null) {
WebDataBinder binder =
resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
if (binder.getTarget() != null) {
doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
}
args[i] = binder.getTarget();
if (assignBindingResult) {
args[i + 1] = binder.getBindingResult();
i++;
}
implicitModel.putAll(binder.getBindingResult().getModel());
}
}
return args;
}
上面方法时携带回了隐藏model赋值。
第二次进入这个方法时是要进入目标方法:
标了注解:首先是扫描注解返回值,如果参数有modelAttribute参数注解。例如(@modelAttribute "haha" ) 拿到modelattribute的值让haha保存
没标注解:先看是否普通参数(是否原生API)
再看是否是Model如果是传入隐匿model
1.先看是否原生API
2.再看是否有model或者map
3.再看是否有其他类型sessionStatus
4.再看是否是普通类型,integer等等 如果是则paparmName=""
5.attrName=""
如果是自定义类型的对象,最终会产生两个结果
1.如果标记了modelAttribute则赋值
2.否则就是空串
下面就是确定自定义类型的参数
else if (attrName != null) {
WebDataBinder binder =
resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
if (binder.getTarget() != null) {
doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
}
args[i] = binder.getTarget();
if (assignBindingResult) {
args[i + 1] = binder.getBindingResult();
i++;
}
implicitModel.putAll(binder.getBindingResult().getModel());
}
}
进入resolveModelAttribute方法
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {
// Bind request parameter onto object...
String name = attrName;
if ("".equals(name)) {
//如果是空串,则将参数类型的小写作为值
name = Conventions.getVariableNameForParameter(methodParam);
}
Class> paramType = methodParam.getParameterType();
Object bindObject;
if (implicitModel.containsKey(name)) {
bindObject = implicitModel.get(name);
}
//如果没有modelAttribute则看session中有没有
else if (this.methodResolver.isSessionAttribute(name, paramType)) {
bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
if (bindObject == null) {
raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
}
}
else {
bindObject = BeanUtils.instantiateClass(paramType);
}
WebDataBinder binder = createBinder(webRequest, bindObject, name);
initBinder(handler, name, binder, webRequest);
return binder;
}
springMVC中pojo的确定
1.如果隐藏模型中有key指定的值则将这个值给bindObject
2.如果是sessionAttribute中标记的对象则在session中找
3.都没有则用反射创建对象
总的来说流程简化版:
1.标了注解,最终得到的注解应该是这个的解析的值
2.看是否是原生API
3.看是否是Model与map
4.都不是看是否是简单类型
5.确定自定义参数:首字母小写或者是对应modelAttribute对应的value值
看隐含模型中是否有对应的key的值如果有就取出来
从sessionAttibute中取
没有标注的话则利用反射创建一个对像
拿到之前创建好的对象就webDATAbinder将每个数据绑定上去
流程总结:页面发起请求,进入dispatchServlet的父类FrameworkServlet中调用doget/dopost方法,doget中有个processRequest方法进去发现调用doservice方法,又在dispatchServlet中找到其doservice方法,进入方法里面会判断是否是文件上传,进入getHandler方法找controller处理器,进入方法扫描所有的handlerMapping进行遍历,其中handlerMapping是springMVC九大组件之一,里面有XML配置的controller与注解型的。拿到处理器再进入getHandlerAdapter方法找对应的适配方法即requestMapping对应的值,遍历所有的handlerAdapter然后获得适配器返回。ha.handle方法调用返回的是modelAndView.进入handle方法来到AnotationMethodHandlerAdapter方法下,首先会new一个隐藏模型map,然后值invokeHandlerMethod执行方法,会扫描所有的modelAttribute的方法现进行处理,封装值。然后再进去映射下的目标方法,都是同一个方法利用resolveHandlerArguments确定参数的,如果有注解就是解析注解信息保存注解信息,没找到注解就看是否是原生API,接着将隐藏模型的Model交给返回的参数,如果是自定义类型的参数进入resolveModelAttribute方法,如果是空串,则将参数类型的小写作为值,然后看modelAttribute中有没有值如果没有的话去sessionAttribute中拿,都没有的话反射创建对象进行封装createBinder。
拿到MV后该返回到页面了, processDispatchResult进入进行将ModelAndView赋值给request与页面视图的拼接。
进入processDispatchResult后再进去render方法进行渲染页面,通过resolveViewName可以得到视图名,进入resolveViewName方法。可以发现她在遍历所有的视图解析器,有默认的也有自己配的,自己的配的前缀后缀就是了,里面有个缓存显示从缓存中拿,没有就创建vie对象,在createView方法中可以看到对页面字符串进行解析比如说看是否是重定向还是转发,都没有就将自己写的前缀后缀拼接然后返回得到View.viw调用render方法,整成一个输出模型将隐藏模型中的model存放在request域中,然后拿到转发器,带上request与response转发到页面。