这里是DispatchServlet中的doDispatch方法,底层思想流程A,B,C,D过程已在下面的源码标注
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//HandlerExecutionChain有三个功能,一是执行对应的控制器方法,二是执行对应的拦截器方法,三是多个拦截器的索引
/*
包含handler、interceptorList、interceptorIndex
handler:浏览器发送的请求所匹配的控制器方法
interceptorList:处理控制器方法的所有拦截器集合
interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行
*/
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
//ModelAndView就是将数据设置到域对象中,并将该模型数据渲染到对应的视图中
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//A.通过对应的请求处理器映射找到对应的控制器方法
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//B.找到与处理器映射对应的处理适配器
//该适配器负责调用控制器方法并确定方法参数的每一个值
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;
}
}
//这里是调用拦截器的applyPreHandle方法(如有多个拦截器按顺序执行)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//C.这里是处理适配器对象调用控制器的方法(该方法的核心功能就是原生Servlet中Service方法,负责处理请求和响应,加上了SpringMVC框架后,更方便的处理请求和响应了)。具体完成的工作有很多,请求参数的数据类型转换,获取请求报文(请求协议),响应报文信息(响应协议),获取模型数据,请求转发和请求重定向等等
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
//这里是执行拦截器的applyPostHandle方法(如有多个拦截器按逆序执行)
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//D.该方法是负责将模型数据渲染到对应的视图中(视图解析和渲染的全过程)
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);
}
}
}
A过程
A. 通过对应的请求处理器映射找到对应的控制器方法( mappedHandler = this.getHandler(processedRequest);)详解
//调用DispatcherServlet类的getHandler方法
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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;
}
//调用AbstractHandlerMapping类的getHandler方法
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//继续调用方法,在这个方法就找到了对应的处理器映射
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
}
//调用AbstractHandlerMapping类的getHandlerInternal方法,该方法是抽象方法,调用对应的实现类方法
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
//调用AbstractHandlerMethodMapping<T>类的getHandlerInternal方法(实现方法)
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//这里是获得请求的URL路径,方便后面进行匹配
String lookupPath = this.initLookupPath(request);
this.mappingRegistry.acquireReadLock();
HandlerMethod var4;
try {
//核心:这里就是真正的匹配内核方法,找到对应请求的处理器映射
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
this.mappingRegistry.releaseReadLock();
}
return var4;
}
//调用AbstractHandlerMethodMapping<T>类的lookupHandlerMethod方法
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
//这里先通过请求的URL路径和处理器映射的路径相比较,得到初步匹配的处理器映射
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
//这里再通过请求方式再进行深入匹配,匹配成功就可以找到对应的处理器映射了
this.addMatchingMappings(directPathMatches, matches, request);
}
}
//调用AbstractHandlerMethodMapping<T>类的addMatchingMappings方法
private void addMatchingMappings(Collection<T> mappings, List<AbstractHandlerMethodMapping<T>.Match> matches, HttpServletRequest request) {
Iterator var4 = mappings.iterator();
//遍历上一过程通过路径匹配成功的处理器映射,再通过请求方式匹配
while(var4.hasNext()) {
T mapping = var4.next();
//请求方式匹配
T match = this.getMatchingMapping(mapping, request);
if (match != null) {
//匹配成功就把该处理器映射添加到集合中
matches.add(new AbstractHandlerMethodMapping.Match(match, (AbstractHandlerMethodMapping.MappingRegistration)this.mappingRegistry.getRegistrations().get(mapping)));
}
}
}
B过程
B.这个过程是根据处理器映射找到对应的适配器
适配器功能:调用控制器方法并确定方法参数(使用参数解析器将请求参数和方法参数进行绑定)的每一个值( HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());)详解
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
//遍历所有的适配器,找到与处理器映射对应的处理器适配器,后续会使用该适配器调用对应的控制器方法(处理器方法)
while(var2.hasNext()) {
//HandlerAdapter是一个接口,所有的适配器类型都实现该接口并重写对应的方法
HandlerAdapter adapter = (HandlerAdapter)var2.next();
//if语句判断是否是对应处理器映射的适配器
//handler都向上转型为Object类型了,通过判断他的实例类型来确定他是那一种处理器的适配器
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");
}
//这是其中一个适配器AbstractHandlerMethodAdapter类的supports方法(用于判断是哪一种处理器的适配器)
public final boolean supports(Object handler) {
return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
}
C过程
C.这里是处理适配器对象调用控制器的方法( mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)
调用控制器方法主要的三个流程:
1.使用相应的方法参数解析器确定方法参数的值
方法参数解析器的定义的规范接口(方法参数解析器的作用)
public interface HandlerMethodArgumentResolver {
//判断实现该接口的解析器是否支持解析该方法参数(一般是通过方法参数的类型和方法参数有没有对应的注解来修饰进行判断)
boolean supportsParameter(MethodParameter parameter);
//支持判断成功后,进行方法参数的解析(也就是确定方法参数的值,不同的方法解析器确定的原理不一样)
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
2.调用方法
3.使用相应的返回值处理器确定方法的返回值(返回值处理器)
public interface HandlerMethodReturnValueHandler {
//判断实现该接口的类是否支持处理该方法的返回值(一般是通过方法返回值的类型和方法参数有没有对应的注解来修饰进行判断)
boolean supportsReturnType(MethodParameter returnType);
//支持判断成功后,返回值处理器回怼方法的返回值进行进一步处理,最后再把处理的结果响应给浏览器
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
C过程源码解析(主要对应上述的三个流程解析)
//调用AbstractHandlerMethodAdapter类的handle方法
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//调用对应的处理方法handleInternal
return this.handleInternal(request, response, (HandlerMethod)handler);
}
//调用AbstractHandlerMethodAdapter类的handleInternal方法,该方法是抽象方法,由他的子类RequestMappingHandlerAdapter来实现
@Nullable
protected abstract ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
//调用RequestMappingHandlerAdapter的handleInternal方法,该方法就真正实现了方法的调用了,前面的都是由抽象找到对应的实体子类,找到了进而实现调用
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
this.checkRequest(request);
ModelAndView mav;
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
//这里就是调用的核心了,可以确定方法参数的值(使用对应的方法解析器),并且也可以确定返回值(使用对应的返回值处理器)
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
//调用RequestMappingHandlerAdapter类的invokeHandlerMethod方法
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
//设置所有的参数解析器,方便后面匹配(有26中方法参数解析器)
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
//设置所有的返回值参数解析器,方便后面匹配
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
//所有解析器准备就绪,可以真正进到方法调用的核心部分了
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (!asyncManager.isConcurrentHandlingStarted()) {
//如果方法参数有Model,Map,或者方法内部设置了域数据,在方法解析器和返回值解析器处理完后,得到了数据Model,也得到了视图view(返回值解析器完成),这里就将mavContainer中的Model和View数据(之前解析好的MOdel和view数据都放在这个容器中了)取出,得到一个ModelAndView对象
ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
return var15;
}
result = null;
} finally {
webRequest.requestCompleted();
}
return (ModelAndView)result;
}
}
//调用 ServletInvocableHandlerMethod类的invokeAndHandle方法
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//调用invokeForRequest方法处理请求,方法参数解析的过程(第一步)
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
try {
//执行完方法后调用该方法处理返回值(第二步)
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (logger.isTraceEnabled()) {
logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
//第一步的源码过程
//核心:调用InvocableHandlerMethod类的invokeForRequest方法(反射来调用方法处理请求)
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//调用getMethodArgumentValues方法进行请求参数和方法参数的绑定,并确定方法的返回值
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
//方法参数和返回值都处理完毕,反射调用该方法处理请求
return this.doInvoke(args);
}
//调用InvocableHandlerMethod类的getMethodArgumentValues进行请求参数和方法参数的绑定(解析方法参数的核心)
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) {
//遍历方法参数解析器,通过方法参数解析器是否支持解析该方法参数(一般是看方法参数是否有对应的注解来修饰进行判断和对应的方法参数类型来判断,还要利用继承先向上转型成父类,该父类实际上是那个类的实例来进行判断,instanceof关键字来实现)来进行判断
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//经过上面的判断已经找到了相应的方法参数解析器了
//参数解析器进行方法参数的解析(一般的参数解析器是进行请求信息和方法参数的绑定,确定方 法参数的值)
//方法参数解析器详解网址:https://segmentfault.com/a/1190000039663265
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
//绑定完毕,返回方法参数数组
return args;
}
}
//第二步的源码过程
//调用HandlerMethodReturnValueHandlerComposite类的handleReturnValue方法
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//遍历所有返回值处理器(解析器),得到对应的返回值处理器(解析器)
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
//使用对应的处理器(解析器)处理返回值(此处便可确定完返回值)
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
//遍历所有的返回值处理器,看那个返回值处理器支持处理该返回值(一般是看方法参数是否有对应的注解来修饰进行判断和对应的方法参数类型来判断,还要利用继承先向上转型成父类,该父类实际上是那个类的实例来进行判断,instanceof关键字来实现)来进行判断
Iterator var4 = this.returnValueHandlers.iterator();
HandlerMethodReturnValueHandler handler;
do {
do {
if (!var4.hasNext()) {
return null;
}
//这里是使用instanceof判断实例的方法来进行判断
handler = (HandlerMethodReturnValueHandler)var4.next();
} while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
} while(!handler.supportsReturnType(returnType));
return handler;
}
C过程番外
1.ServletModelAttributeMethodProcessor方法参数解析器详解
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
String name = ModelFactory.getNameForParameter(parameter);
ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null) {
mavContainer.setBinding(name, ann.binding());
}
Object attribute = null;
BindingResult bindingResult = null;
if (mavContainer.containsAttribute(name)) {
attribute = mavContainer.getModel().get(name);
} else {
try {
//创建pojo对象并获取请求过来的参数属性
attribute = this.createAttribute(name, parameter, binderFactory, webRequest);
} catch (BindException var10) {
if (this.isBindExceptionRequired(parameter)) {
throw var10;
}
if (parameter.getParameterType() == Optional.class) {
attribute = Optional.empty();
} else {
attribute = var10.getTarget();
}
bindingResult = var10.getBindingResult();
}
}
if (bindingResult == null) {
//利用数据绑定工厂创建 WebDataBinder数据绑定器对象(进行请求参数和pojo对象属性的数据绑定)
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
//进行请求参数和pojo对象属性的数据绑定(数据绑定器内含各种数据转换器(遍历数据转换器找到适合的数据转换器进行数据转换),将请求参数的字符串类型转换为对象属性对应的类型,再利用反射进行赋值)
this.bindRequestParameters(binder, webRequest);
}
this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
if (!parameter.getParameterType().isInstance(attribute)) {
attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
bindingResult = binder.getBindingResult();
}
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return attribute;
}
2.RequestResponseBodyMethodProcessor返回值处理器处理详解
是用来处理@ResponseBody 注解的,底层采用流的方式给客户端回传数据(底层是客户端和服务器内容协商原理)
内容协商原理思想:
1.根据客户端发送的请求判断客户端可接受的数据类型(请求头中获取)
2.获取服务器自身可产生的消息类型。通过遍历消息转换器,找到能将方法返回值转换成消息类型的消息转换器,就说明服务器可产生该消息类型
3.客户端可接受的数据和服务器可产生的数据类型进行最匹配,得到匹配成功的消息类型的集合(困难会有多个类型成功匹配,因此是集合)
4.将匹配成功的集合按照客户端可接受的数据的权重进行排序(排序后取其权重最高的消息类型),也称最佳匹配
5.再次遍历所有的消息转换器,找到可将方法返回值转换成最佳匹配消息类型的消息转换器,使用该消息转换器进行类型转换,转换成功把数据使用流的方式相应到客户端
源码详解
//调用RequestResponseBodyMethodProcessor类的handleReturnValue来处理返回值
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
//获取原生的请求信息和响应信息
ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
//处理核心
this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//MediaType:浏览器和服务器能相互传输的数据类型。electedMediaType:匹配成功的数据类型
MediaType selectedMediaType = null;
try {
//1、根据客户端发送的请求判断客户端可接受的数据类型(最底层是从请求头中获取)
acceptableTypes = this.getAcceptableMediaTypes(request);
}
//2.获取服务器自身可产生的消息类型。通过遍历消息转换器,找到能将方法返回值转换成消息类型的消息转换器,就说明服务器可产生该消息类型
List<MediaType> producibleTypes = this.getProducibleMediaTypes(request, valueType, (Type)targetType);
//3.客户端可接受的数据和服务器可产生的数据类型进行最匹配,得到匹配成功的消息类型的集合(因为会有多个类型成功匹配,因此是集合)
while(var17.hasNext()) {
MediaType producibleType = (MediaType)var17.next();
if (mediaType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(this.getMostSpecificMediaType(mediaType, producibleType));
}
}
//4.将匹配成功的集合按照客户端可接受的数据的权重进行排序(排序后取其权重最高的消息类型),也称最佳匹配
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
var15 = mediaTypesToUse.iterator();
//遍历排序后的集合,取其权重最高的消息类型,取到立刻break退出循环
while(var15.hasNext()) {
mediaType = (MediaType)var15.next();
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
HttpMessageConverter converter;
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
Iterator var23 = this.messageConverters.iterator();
//5.再次遍历所有的消息转换器,找到可将方法返回值转换成最佳匹配消息类型的消息转换器,使用该消息转换器进行类型转换,转换成功把数据使用流的方式相应到客户端
while(var23.hasNext()) {
converter = (HttpMessageConverter)var23.next();
genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;
if (genericConverter != null) {
if (((GenericHttpMessageConverter)converter).canWrite((Type)targetType, valueType, selectedMediaType)) {
break label183;
}
//这里就是第五步的核心
//valueType:方法返回值 selectedMediaType:匹配到的最佳的消息类型
} else if (converter.canWrite(valueType, selectedMediaType)) {
break label183;
}
}
}
}
细节:内容协商策略有两种,一种请求参数式的内容协商(供我们利用请求参数手动设置客户端想要接受的消息类型) ,另一种则是默认使用请求头中(因为请求头中有默认的客户端想要接受的消息类型)的内容协商策略
D过程
D.该方法是负责将模型数据渲染到对应的视图中(视图解析和渲染的全过程)
可根据视图接口自定义视图解析器
视图解析底层思想:
1、目标方法处理的过程中,所有数据都会被放在 ModelAndViewContainer 容器里面。包括数据和视图地址
2、 把ModelAndViewContainer 容器里的Model数据和视图地址取出,把这些数据放入ModelAndViewContainer对象中
3、任何目标方法执行完成以后最终都会返回 ModelAndView (数据和视图地址),好让后续逻辑专注于处理模型和视图地址
4、processDispatchResult 处理派发结果(页面该如何响应)
a.得到视图对象,所有视图解析器尝试将视图地址解析成视图对象(我们使用的是ThymeleafViewResolver解析器)
b.得到视图对象后,利用Thymeleaf的模板引擎将模型数据渲染到视图中,最后再根据视图对象是转发,还是重定向进行页面跳转
具体源码详解
//调用DispatcherServlet类的processDispatchResult方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
if (mv != null && !mv.wasCleared()) {
//render方法(视图解析和渲染核心方法)
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No view rendering, null ModelAndView returned.");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
//执行拦截器的最后的一个方法AfterCompletion。(如有多个拦截器按逆序执行)
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
//调用DispatcherServlet类的render方法
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
response.setLocale(locale);
//得到视图名
String viewName = mv.getViewName();
View view;
if (viewName != null) {
//a.得到视图对象,所有视图解析器尝试将视图地址解析成视图对象(我们使用的是ThymeleafViewResolver解析器)
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
response.setStatus(mv.getStatus().value());
}
//b.得到视图对象后,利用Thymeleaf的模板引擎将模型数据渲染到视图中,最后再根据视图对象是转发,还是重定向进行页面跳转
view.render(mv.getModelInternal(), request, response);
} catch (Exception var8) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "]", var8);
}
throw var8;
}
}
a.得到视图对象,所有视图解析器尝试将视图地址解析成视图对象(我们使用的是ThymeleafViewResolver解析器)详解
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
//调用ContentNegotiatingViewResolver类的resolveViewName方法
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
//得到客户端能接受的媒体类型(数据类型)
List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
if (requestedMediaTypes != null) {
//返回成功解析的视图对象(内涵视图解析器能否解析视图地址的过程)
List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
//把视图对象进行进一步筛选,得到最匹配的视图对象
View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
String mediaTypeInfo = this.logger.isDebugEnabled() && requestedMediaTypes != null ? " given " + requestedMediaTypes.toString() : "";
if (this.useNotAcceptableStatusCode) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
}
return NOT_ACCEPTABLE_VIEW;
} else {
this.logger.debug("View remains unresolved" + mediaTypeInfo);
return null;
}
}
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {
List<View> candidateViews = new ArrayList();
if (this.viewResolvers != null) {
Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
Iterator var5 = this.viewResolvers.iterator();
//遍历所有的视图解析器,判断那个视图解析能解析视图地址并返回解析成功的视图对象
while(var5.hasNext()) {
ViewResolver viewResolver = (ViewResolver)var5.next();
//解析过程
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
candidateViews.add(view);
}
return candidateViews;
}
//调用AbstractCachingViewResolver类的resolveViewName方法(这是其中的一个视图解析器的解析过程)
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (!this.isCache()) {
//这里实质是他的子类ThymeleafViewResolver类进行解析过程
return this.createView(viewName, locale);
}
}
//调用ThymeleafViewResolver类的createView方法
protected View createView(String viewName, Locale locale) throws Exception {
if (!this.alwaysProcessRedirectAndForward && !this.canHandle(viewName, locale)) {
vrlogger.trace("[THYMELEAF] View \"{}\" cannot be handled by ThymeleafViewResolver. Passing on to the next resolver in the chain.", viewName);
return null;
} else {
String forwardUrl;
//判断是否是重定向
if (viewName.startsWith("redirect:")) {
vrlogger.trace("[THYMELEAF] View \"{}\" is a redirect, and will not be handled directly by ThymeleafViewResolver.", viewName);
forwardUrl = viewName.substring("redirect:".length(), viewName.length());
RedirectView view = new RedirectView(forwardUrl, this.isRedirectContextRelative(), this.isRedirectHttp10Compatible());
return (View)this.getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, "redirect:");
//判断是否是转发
} else if (viewName.startsWith("forward:")) {
vrlogger.trace("[THYMELEAF] View \"{}\" is a forward, and will not be handled directly by ThymeleafViewResolver.", viewName);
forwardUrl = viewName.substring("forward:".length(), viewName.length());
return new InternalResourceView(forwardUrl);
} else if (this.alwaysProcessRedirectAndForward && !this.canHandle(viewName, locale)) {
vrlogger.trace("[THYMELEAF] View \"{}\" cannot be handled by ThymeleafViewResolver. Passing on to the next resolver in the chain.", viewName);
return null;
} else {
vrlogger.trace("[THYMELEAF] View {} will be handled by ThymeleafViewResolver and a {} instance will be created for it", viewName, this.getViewClass().getSimpleName());
return this.loadView(viewName, locale);
}
}
}
//把视图对象进行进一步筛选,得到最匹配的视图对象
//调用ContentNegotiatingViewResolver类的getBestView方法
@Nullable
private View getBestView(List<View> candidateViews, List<MediaType> requestedMediaTypes, RequestAttributes attrs) {
Iterator var4 = candidateViews.iterator();
while(var4.hasNext()) {
View candidateView = (View)var4.next();
//遍历初步匹配的视图,判断视图是否是SmartView接口(他的实例有两个,一个是重定向视图,一个是ajax请求的重定向视图)的实例,如果是直接返回
if (candidateView instanceof SmartView) {
SmartView smartView = (SmartView)candidateView;
if (smartView.isRedirectView()) {
return candidateView;
}
}
}
//以下是内容协商的过程,如果不是重定向视图,要根据内容协商来确认最匹配的视图,内容协商原理上面有,救不重复了
var4 = requestedMediaTypes.iterator();
while(var4.hasNext()) {
MediaType mediaType = (MediaType)var4.next();
Iterator var10 = candidateViews.iterator();
while(var10.hasNext()) {
View candidateView = (View)var10.next();
if (StringUtils.hasText(candidateView.getContentType())) {
MediaType candidateContentType = MediaType.parseMediaType(candidateView.getContentType());
if (mediaType.isCompatibleWith(candidateContentType)) {
mediaType = mediaType.removeQualityValue();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Selected '" + mediaType + "' given " + requestedMediaTypes);
}
attrs.setAttribute(View.SELECTED_CONTENT_TYPE, mediaType, 0);
return candidateView;
}
}
}
}
return null;
}
b.得到视图对象后,利用Thymeleaf的模板引擎将模型数据渲染到视图中,最后再根据视图对象是转发,还是重定向进行页面跳转(详解) view.render(mv.getModelInternal(), request, response);
具体源码
//调用AbstractView的render方法(渲染过程)
public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (this.logger.isDebugEnabled()) {
this.logger.debug("View " + this.formatViewName() + ", model " + (model != null ? model : Collections.emptyMap()) + (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
}
//把Model模型数据提取到集合中
Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);
this.prepareResponse(request, response);
//进行模型数据渲染到页面的过程
//因为不同视图View的渲染过程不一样,所以这里是调用抽象的AbstractView的render方法,具体的渲染过程由this,看他的实际的子类视图是那个,就调用那个子类的渲染方法(多态实现)
this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);
}
//子类视图是重定向RedirectView视图,所以调用RedirectView类的渲染方法renderMergedOutputModel
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws IOException {
//获取视图地址
String targetUrl = this.createTargetUrl(model, request);
targetUrl = this.updateTargetUrl(targetUrl, model, request, response);
RequestContextUtils.saveOutputFlashMap(targetUrl, request, response);
//进行视图地址的重定向跳转
this.sendRedirect(request, response, targetUrl, this.http10Compatible);
}
//调用RedirectView类的渲染方法sendRedirect方法
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String targetUrl, boolean http10Compatible) throws IOException {
String encodedURL = this.isRemoteHost(targetUrl) ? targetUrl : response.encodeRedirectURL(targetUrl);
HttpStatus attributeStatusCode;
if (http10Compatible) {
attributeStatusCode = (HttpStatus)request.getAttribute(View.RESPONSE_STATUS_ATTRIBUTE);
if (this.statusCode != null) {
response.setStatus(this.statusCode.value());
response.setHeader("Location", encodedURL);
} else if (attributeStatusCode != null) {
response.setStatus(attributeStatusCode.value());
response.setHeader("Location", encodedURL);
} else {
//重定向
response.sendRedirect(encodedURL);
}
} else {
attributeStatusCode = this.getHttp11StatusCode(request, response, targetUrl);
response.setStatus(attributeStatusCode.value());
response.setHeader("Location", encodedURL);
}
}
doDispatch方法调用总结
大致过程:获取对应的处理器映射->得到对应的处理器适配器->处理器适配器进行方法的调用->方法调用完后进行视图的解析和渲染
注意:由于框架涉及的解耦性和拓展性,主要运用多态的方式来实现框架的解耦性和拓展性(都是运用this来进行方法的调用,实质就是多态的过程),用绑定配置文件的方式进行原有代码的维护(这样就可以在不改动原有的代码的情况下进行属性的修改)。所以上面的源码这是针对某些具体的实现来进行的,并不代表全部的源码实现,只是借助某一部分的实现来深入了解该框架的涉及思想。除此此外还内含大量的设计模式,在这方面我还没有深入研究。