一、前端控制器的架构?DispatcherServlet
二、doDispatch()详细细节:
@RequestMapping("/updateBook")
public String updateBook(@RequestParam(value="author")String author,
Map<String, Object> model,
HttpServletRequest request,
@ModelAttribute("haha") Book book
){
o2 = model;
b2 = book;
Object haha = model.get("haha");
//System.out.println("传入的model:"+model.getClass());
System.out.println("o1==o2?"+(o1 == o2));
System.out.println("b1==b2?"+(b1 == b2)+"-->"+(b2 == haha));
System.out.println("页面要提交过来的图书信息:"+book);
return "success";
}
// @ModelAttribute("haha")
@ModelAttribute
public void hahaMyModelAttribute(Map<String, Object> map){
Book book = new Book(100, "西游记", "吴承恩", 98, 10, 98.98);
System.out.println("数据库中查到的图书信息是:"+book);
map.put("book", book);
b1 = book;
o1 = map;
System.out.println("modelAttribute方法...查询了图书并给你保存起来了...他用的map的类型:"+map.getClass());
}
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 {
//1、检查是否文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
//2、根据当前的请求地址找到目标处理器(哪个Controller)类;
mappedHandler = getHandler(processedRequest);
//3、如果没有找到哪个处理器(控制器)能处理这个请求就404,或者抛异常
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//4、拿到能执行这个类的所有方法的适配器;(反射工具AnnotationMethodHandlerAdapter)
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()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.处理(控制)器的方法被调用
//控制器(Controller),处理器(Handler)
//5、适配器来执行目标方法;将目标方法执行完成后的返回值作为视图名,设置保存到ModelAndView中
//目标方法无论怎么写,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);//如果没有视图名设置一个默认的视图名;
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//转发到目标页面;
//6、根据方法最终执行完成后封装的ModelAndView;转发到对应页面,而且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
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
1、所有请求过来DispatcherServlet收到请求,
2、调用doDispatch()方法进行处理
- ①getHandler():根据当前请求地址找到能处理这个请求的目标处理器类(Controller类)根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
- ②getHandlerAdapter():根据当前处理器类获取到能执行这个处理器方法的适配器;根据当前处理器类,找到当前类的HandlerAdapter(适配器)
- ③使用刚才获取到的适配器(AnnotationMethodHandlerAdapter )执行目标方法;
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- ④目标方法执行后会返回一个ModelAndView对象
- ⑤根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView中的模型数据
三、getHandler()细节:怎么根据当前请求就能找到哪个类能来处理
HandlerMapping:处理器映射:他里面保存了每一个处理器能处理哪些请求的映射信息;
handlerMap:ioc容器启动创建Controller对象的时候扫描每个处理器(Controller)都能处理什么请求,保存在HandlerMapping的handlerMap属性中;
下一次请求过来,就来看哪个HandlerMapping中有这个请求映射信息就行了;
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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;
}
查看handlerMappings,有两个对象,【0】配置资源部 【1】注解资源部
getHandler()会返回目标处理器类的执行链;
四、getHandlerAdapter细节,如何找到目标处理器类的适配器,然后拿适配器才去执行目标方法
AnnotationMethodHandlerAdapter:能解析注解方法的适配器;处理器类(Controller类)中只要有标了注解的方法就能用;
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
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");
}
五、doDispatch()的适配器执行handle方法细节
1、handle里面return invokeHandlerMethod代码细节解析
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);
//包装原生的request, response,
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//创建了一个,隐含模型(implicit:含蓄的)
ExtendedModelMap implicitModel = new BindingAwareModelMap();
//真正执行目标方法;目标方法利用反射执行期间确定参数值,提前执行modelattribute等所有的操作都在这个方法中; args:目标方法,处理器类,request和response的包装类,隐含模型
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;
}
2、invokeHandlerMethod方法执行的细节:
publicfinal Object invokeHandlerMethod(Method handlerMethod, Object handler,
NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
//获取到执行方法
Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);//目标方法
try {
boolean debug = logger.isDebugEnabled();
//拿到所有的@SessionAttribute注解中所有的value(数组),遍历每一个value,
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
//从sessionAttribute存储区中查询出来
Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
if (attrValue != null) {
//隐含模型第一次有值
//若@SessionAttribute标注的属性value在session中有值,他会把这些拿来放在隐含模型中
implicitModel.addAttribute(attrName, attrValue);
}
}
//找到所有@ModelAttribute注解标注的方法;
for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
//遍历一个标了@ModelAttribute的方法
Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
//先确定modelattribute方法执行时要使用的每一个参数的值;
Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
if (debug) {
logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
}
String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();//获取方法上标注的@ModelAttribute注解的value对应的key值 ,作为ModelAttribute方法的返回值,若没有则先把attrName设为“”,即空串
if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
continue;
}
ReflectionUtils.makeAccessible(attributeMethodToInvoke);//利用反射把该方法置为可访问的
//提前运行ModelAttribute,
Object attrValue = attributeMethodToInvoke.invoke(handler, args);
if ("".equals(attrName)) {//若attrName为空串,即方法上的@ModeAttribute没有value属性
Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());//解析并获取返回值类型
attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);//为返回值类型起一个变量名,void 则为"void" Book返回值则为"book",返回值类型首字母小写
}
//把提前运行的ModelAttribute方法的返回值也放在隐含模型中
if (!implicitModel.containsAttribute(attrName)) {
implicitModel.addAttribute(attrName, attrValue);
}
}
//获取@ModleAttribute标记的方法的参数并且利用反射执行该方法后,就要执行目标方法了
//再次解析目标方法参数是哪些值
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;
}
}
1)、拿到所有的@SessionAttribute注解中所有的value(数组),遍历每一个value,若@SessionAttribute标注的属性value在session中有值,他会把这些拿来放在隐含模型中(隐含模型第一次有值)
2)、找到所有@ModelAttribute注解标注的方法,遍历
-
①拿到第一个标了@ModelAttribute的方法,确定该方法执行时要使用的每一个参数的值(在后面会详细讲);
-
②获取方法上标注的@ModelAttribute注解的value属性对应的key值 并且赋值给attrName,若没有value则先把attrName设为“”,即空串
-
③利用反射把该方法置为可访问的然后利用反射提前运行该方法,并且得到方法运行结果的返回值 赋值给attrValue(null)
-
④若attrName为"" ,则解析方法并且获取方法的返回值类型,然后赋值attrName=返回值类型首字母小写(方法返回值void 则为"void" ,返回值Book则为"book")
-
⑤把提前运行的ModelAttribute方法的返回值放在隐含模型中 implicitModel.addAttribute(attrName, attrValue);
3)、解析目标方法参数,然后执行目标方法
3、确定方法运行时使用的每一个参数的值resolveHandlerArguments方法代码解析(Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
)
这里就不示范@ModelAttribute的方法的参数确定(只有一个Map参数而已),直接示范目标方法的参数确定过程。
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++) {
//整成SpringMVC可以处理的方法的参数
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();
//找到目标方法第i个参数的所有注解,如果有注解就解析并保存注解的信息;
for (Annotation paramAnn : paramAnns) {
if (RequestParam.class.isInstance(paramAnn)) {
RequestParam requestParam = (RequestParam) paramAnn;
//拿到注解的value值,赋值给paremName;
paramName = requestParam.value();
//拿到注解的required值,赋值给required;
required = requestParam.required();
//拿到注解的defaultValue值,赋值给defaultValue;
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 if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
validate = true;
Object value = AnnotationUtils.getValue(paramAnn);
validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
}
}
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) {
//解析普通参数-->会进入resolveStandardArgument(解析标准参数)
Object argValue = resolveCommonArgument(methodParam, webRequest);
if (argValue != WebArgumentResolver.UNRESOLVED) {//参数不等于未解析,即解析成功(若解析失败,即当前的参数不是原生API,如当前为Map,则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.");
}
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);//给参数绑定值,若有@ModelAttribute中找到参数的对象,则在该参数基础上进行参数的绑定
}
args[i] = binder.getTarget();
if (assignBindingResult) {
args[i + 1] = binder.getBindingResult();
i++;
}
implicitModel.putAll(binder.getBindingResult().getModel());
}
}
return args;
}
过程如下:
1、获取到一个方法的所有参数
2、创建了一个和参数个数一样多的数组,会用来保存每一个参数的值 Object[] args = new Object[paramTypes.length];
3、遍历每个参数,解析参数类型
- 找到当前方法当前遍历到的参数的所有注解,若有注解,解析并保存注解的信息; 如果参数有ModelAttribute注解;拿到ModelAttribute注解的值让attrName保存attrName=“haha”
实在写不下去了,太多了5555555,贴流程吧。。。
//确定值的环节
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;