jdbc编程的时候是一个Servlet对应一个接口,如果一个项目的接口有成百上千个,那我们也必须创建成百上千个Servlet,造成的工作量可想而知。现在有springmvc框架解决了jdbc时代开发慢的限制。
这时要说到springmvc提供的DispatcherServlet,以下是的继承结构:
蓝色背景的是类,绿色的接口,标红的方法是核心的方法。从HttpServlet这个类开始及后面的父类都是javax.servlet包提供的类,从HttpServletBean类开始往前都是springmvc提供的,也就是说DispatcherServlet继承了Servlet,所有的请求操作都是在这个DispatcherServlet完成的,那下面分析一下那么多Servlet具体是干什么的:
1、Servlet:定义函数
init(…):第一次请求会触发
service():可以获取前台一些请求参数,具体的业务代码
destory():销毁
2、GenericServlet:
init(…):赋值ServletConfig (web一些配置信息)
init():留给子类覆盖
3、HttpServlet:
doGet()、doPost()等方法
service (req, resp):实现父类的service()判断是get、post等请求
4、HttpServletBean:
init():实现GenericServlet的init()方法,获取初始化配置参数
initServletBean():留给子类实现
5、FrameworkServlet:
initServletBean():实现HttpServletBean,初始化上下文Context
processRequest(req, resp):调用doService()方法,该方法被doGet,doPost调用
doService(req, resp):留给子类实现
6、DispatcherServlet:
doService(req, resp):实现父类FrameworkServlet的方法,调用doDispatch()
doDispatch(req, resp):核心方法
接下来主要对doDispatch这个方法做具体的讲解:
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 {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 根据请求信息获取映射处理器
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 根据映射处理器获取相应的处理器适配器
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;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
// 后置拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
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️⃣、根据请求信息获取处理器映射
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;
}
针对上述代码主要考虑2部分
一、
处理器映射HandlerMapping
集合是如何注册的。
二、
根据请求是如何获取处理器执行链(HandlerExecutionChain
)的。
对于一:首先要了解servlet
的加载机制,第一次请求的时候会调用init
方法,该方法执行的时候会注册相关的处理器映射,看下代码:
// 初始化策略(在init方法加载的时候调用)
protected void initStrategies(ApplicationContext context) {
// 注册多文件上传解析器
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
// 注册处理器映射器
this.initHandlerMappings(context);
// 注册处理器适配器
this.initHandlerAdapters(context);
// 注册处理器异常解析器
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
// 注册视图解析器
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
继续追踪this.initHandlerMappings(context)
:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 默认加载Spring容器里的处理器映射器(可自定义映射器)
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
// 根据名称获取Spring容器里的处理器映射器
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {
;
}
}
// 如果容器里找不到处理器映射器则默认
// 从DispatcherServlet.properties文件中加载
if (this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
注册处理器映射器主要分为两个步骤:
1)、如果设置允许检测全部的处理器映射器,则会根据HandlerMapping
类型从Spring容器里面加载,否则根据'handlerMapping'
名称获取一个处理器。
2)、如果Spring容器里没有注册相关的处理器,则从配置文件DispatcherServlet.properties
加载默认的处理器。
现在知道了处理器映射器的加载过程,HandlerMapping
有很多不同的实现类,每个实现类都表示不同的注册方式,比如常用的@Controller、@RequestMapping
注解都属于同一种注册方式对应的处理器映射器是RequestMappingHandlerMapping
,还有一种则是基于实现Controller注解的方式对应的处理器映射器是BeanNameUrlHandlerMapping
,下面针对这俩种处理器映射器进行讲解:
1:RequestMappingHandlerMapping
:可以看到它的其中一个父类是InitializingBean
,InitializingBean
是个接口表示在Spring容器bean初始化填充数据完成后进行的额外操作,此处的作用是帮助RequestMappingHandlerMapping
从Spring容器中获取带有@Controller/@RequestMapping
注解的类信息,并且统计该类的带有@RequestMapping
的方法,以RequestMappingInfo(存放RequestMapping注解的信息)
为Key,HandlerMethod
为value存入Map集合
,下面看一下代码实现:
// RequestMappingHandlerMapping初始化填充数据完成后调用(入口)
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
// 初始化处理器方法(Controller的方法)
protected void initHandlerMethods() {
// 扫描Spring容器获取全部的beanName
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
// 过滤掉beanName前缀为scopedTarget的bean
if (!beanName.startsWith("scopedTarget.")) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) { //... }
// 获取beanType类的注解有@Controller及包含@Controller的注解(@RestController)或者@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
// 在指定的bean, 查找处理器方法
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
// 处理器类型
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取Method对应@RequestMapping注解信息的Map集合
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// 封装@RequestMapping信息
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
// 以mapping为Key,method为value存入map
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
2:BeanNameUrlHandlerMapping
: 利用了父类ApplicationContextAware
接口的特性,和InitializingBean
方法的调用时机类似都是在bean初始化填充数据完成后调用的,而ApplicationContextAware
的setApplicationContext
是通过BeanPostProcessor
的实现类ApplicationContextAwareProcessor
的postProcessBeforeInitialization
方法调用实现的。
初始化处理器方法是在setApplicationContext
@Override
// bean初始化填充数据完成后调用
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
// 检测处理器
detectHandlers();
}
// 检测处理器并注册
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
// 从Spring获取beanName
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// 注册处理器
registerHandler(urls, beanName);
}
}
}
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
// 循环Path
for (String urlPath : urlPaths) {
registerHandler(urlPath, beanName);
}
}
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
setDefaultHandler(resolvedHandler);
}
else {
// 以UrlPath为Key,Handler为value
this.handlerMap.put(urlPath, resolvedHandler);
}
}
}
对于如何注册处理器映射器及它的初始化做了哪些操作在上述已经讲解,接下来讲一下根据请求信息是如何获取处理器执行链HandlerExecutionChain
,也就是第二部分
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 抽象出来给子类实现(根据请求获取处理器)
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 执行链主要包含处理器和拦截器
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
总结:这部分的目的主要是为了获取Handler处理器
2️⃣、根据上面步骤的结果获取Handler处理器来获取处理器适配器(适配器的目的主要是根据Controller不同的实现方式做相应的处理,例如注解@Controller、接口Controller的方式)
// 获取符合条件的处理器适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter ha : this.handlerAdapters) {
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");
}
这段代码和获取处理器映射器很相似,现在看一下适配器是如何注册及初始化的,处理器映射器的讲解中已经讲到了它的注册方式,都是通过调用Servlet
的init
方法注册及初始化的this.initHandlerAdapters(context)
// 初始化处理器适配器(代码的流程和处理器映射器一样)
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
}
}
HandlerAdapter
的实现类,分别有RequestMappingHandlerAdapter
、SimpleControllerHandlerAdapter
,分别对应HandlerMapping
的实现类有RequestMappingHandlerMapping
、BeanNameUrlHandlerMapping
。
RequestMappingHandlerAdapter
的初始化方式也和RequestMappingHandlerMapping
一样都是通过实现InitializingBean
// 初始化参数转换器(参数解析器对应参数转换器)
public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
this.messageConverters = new ArrayList<>(4);
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
this.messageConverters.add(new SourceHttpMessageConverter<>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
// 初始化参数、返回值解析器
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
// 初始化处理器参数解析器
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 初始化绑定器参数解析器
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 初始化处理器返回值解析器
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
这些解析器都是对不同的操作阶段做不同的处理,比如HandlerMethodArgumentResolver
是对HandlerMethod
的参数做解析,@RequestParam、@RequestBody、@ModelAttribute
等注解都有对应的解析器。
HandlerMethodReturnValueHandler
返回值处理器是对HandlerMethod
的返回值做处理,如@ResponseBody、ModelAndView
等注解及反正值类型也都有相应的处理器,下面针对这俩种解析器分别找一个常用的实现类进行讲解:
RequestResponseBodyMethodProcessor
: 是对带有@RequestBody
进行解析
// 调用处理器:包括参数的解析、返回值的处理
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 根据参数值获取返回值:method.invoke(obj, args)
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 对返回值做处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
throw ex;
}
}
// 参数解析及获取返回值
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取参数信息
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// 反射出返回值
Object returnValue = doInvoke(args);
return returnValue;
}
// 解析参数
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
// 参数转换器(将请求的参数转换成实体对象)
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return adaptArgumentIfNecessary(arg, parameter);
}
// 参数转换
@Override
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null, "No HttpServletRequest");
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
// 参数转换
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getExecutable().toGenericString());
}
return arg;
}
// 查找符合条件的转换器:例如:@RequestBody的转换,@RequestParam的转换
// 由AbstractMessageConverterMethodArgumentResolver实现
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType;
boolean noContentType = false;
try {
// 获取请求类型
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
// 默认类型
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
// @Controller标注的类
Class<?> contextClass = parameter.getContainingClass();
// 参数的类型
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class<T>) resolvableType.resolve();
}
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;
EmptyBodyCheckingHttpInputMessage message;
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (message.hasBody()) {
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
} else {
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
}
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
return body;
}
以上代码是对一个请求参数的转换过程,大概流程就是根据方法参数的标注注解来获取相应的转换器HttpMessageConverter
进行参数read的解析,下面对返回值write的操作进行讲解,对与不同的返回类型会有不同处理:
比如对@ResponseBody
标注的处理器方法对应的处理器是RequestResponseBodyMethodProcessor
对应的转换器是MappingJackson2HttpMessageConverter
它的的实现方式:
@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);
// 对返回值的转换解析
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
// 对返回值的转换解析
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object outputValue;
Class<?> valueType;
Type declaredType;
if (value instanceof CharSequence) {
outputValue = value.toString();
valueType = String.class;
declaredType = String.class;
}
else {
outputValue = value;
valueType = getReturnValueType(outputValue, returnType);
declaredType = getGenericType(returnType);
}
if (isResourceType(value, returnType)) {
outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null) {
Resource resource = (Resource) value;
try {
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
outputValue = HttpRange.toResourceRegions(httpRanges, resource);
valueType = outputValue.getClass();
declaredType = RESOURCE_REGION_LIST_TYPE;
}
catch (IllegalArgumentException ex) {
outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
}
}
}
List<MediaType> mediaTypesToUse;
MediaType contentType = outputMessage.getHeaders().getContentType();
if (contentType != null && contentType.isConcrete()) {
mediaTypesToUse = Collections.singletonList(contentType);
}
else {
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
if (outputValue != null && producibleMediaTypes.isEmpty()) {
throw new HttpMessageNotWritableException(
"No converter found for return value of type: " + valueType);
}
mediaTypesToUse = new ArrayList<>();
for (MediaType requestedType : requestedMediaTypes) {
for (MediaType producibleType : producibleMediaTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (mediaTypesToUse.isEmpty()) {
if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
return;
}
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
}
MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypesToUse) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(declaredType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
outputValue = getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (outputValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
// 写入操作
if (genericConverter != null) {
genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage);
}
}
return;
}
}
}
if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
// 看到这可以看到熟悉的代码了
@Override
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
MediaType contentType = outputMessage.getHeaders().getContentType();
JsonEncoding encoding = getJsonEncoding(contentType);
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
try {
writePrefix(generator, object);
Object value = object;
Class<?> serializationView = null;
FilterProvider filters = null;
JavaType javaType = null;
if (object instanceof MappingJacksonValue) {
MappingJacksonValue container = (MappingJacksonValue) object;
value = container.getValue();
serializationView = container.getSerializationView();
filters = container.getFilters();
}
if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
javaType = getJavaType(type, null);
}
ObjectWriter objectWriter = (serializationView != null ?
this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer());
if (filters != null) {
objectWriter = objectWriter.with(filters);
}
if (javaType != null && javaType.isContainerType()) {
objectWriter = objectWriter.forType(javaType);
}
SerializationConfig config = objectWriter.getConfig();
if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&
config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
objectWriter = objectWriter.with(this.ssePrettyPrinter);
}
// 将返回值进行Json转换
objectWriter.writeValue(generator, value);
writeSuffix(generator, object);
// 进行响应
generator.flush();
}
catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
}
}
以上代码是RequestResponseBodyMethodProcessor、MappingJackson2HttpMessageConverter
是对@ResponseBody
标注方式的实现过程。在前后端未分离前,都是由后端渲染页面的,最常用的就是jsp
页面,Spring到底是怎样返回页面的。ViewNameMethodReturnValueHandler
是针对于视图名称方法返回值的处理器(一般是前端页面的路径)
ViewNameMethodReturnValueHandler
的实现方式
// 支持空类型或字符串类型的返回值
@Override
public boolean supportsReturnType(MethodParameter returnType) {
Class<?> paramType = returnType.getParameterType();
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
}
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 返回值是字符串类型的情况下
if (returnValue instanceof CharSequence) {
String viewName = returnValue.toString();
// 设置视图名称
mavContainer.setViewName(viewName);
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null) { //解释了视图类型必须是空值、或字符串
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
现在获取到了ModelAndView
,后面就是根据这个ModelAndView
获取匹配的视图解析器ViewResolver
,然后再解析出View
视图,最后根据view.render()
渲染页面(页面转发)
// 执行完适配器获取视图`ModelAndView`之后调用此方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 页面转发的核心代码(返回json格式数据的处理器不执行此段代码)
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
// 视图渲染
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 解析视图名称获取视图对象
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 视图渲染
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
throw ex;
}
}
// 根据视图名称获取视图
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
// 视图渲染
@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
// 由子类实现
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
// 视图转发(底层)
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置request属性
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
rd.include(request, response);
}
else {
rd.forward(request, response);
}
}
现在springmvc
的整个请求流程都已经讲解结束,下面做一下总结:
1、根据请求信息获取处理器映射器(RequestMappingHandlerMapping(@Controller标注)
、BeanNameUrlHandlerMapping(继承Controller)
)来获取指定的HandlerExecutionChain(包含HandlerMethod、HandlerInterceptor拦截器)
2、根据1步骤
的HandlerMethod
来获取合适的HandlerAdapter
,主要包括:RequestMappingHandlerAdapter(@Controller\@RequestMapping标注)、SimpleControllerHandlerAdapter(继承Controller)
,然后根据适配器初始化注册的HandlerMethodArgumentResolver(HttpMessageConverter)、HandlerMethodReturnValueHandler(HttpMessageConverter)
获取ModelAndView
3、根据步骤2
的ModelAndView
来获取ViewResolver
视图解析器解析出View
视图对象,进一步对视图进行渲染转发
可以发现步骤1\2\3处理器、适配器、解析器都是在DispatcherServlet
的初始化函数中注册的