文章目录
spring mvc 初始化工作
当 org.springframework.web.servlet.FrameworkServlet#onApplicationEvent(ContextRefreshedEvent event)
监听到 ContextRefreshedEvent
事件时,则会调用子类中的 onRefresh(ApplicationContext context)
的 initStrategies
方法进行初始化工作处理
org.springframework.web.servlet.DispatcherServlet.initStrategies
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
initHandlerMappings 初始化
org.springframework.web.servlet.DispatcherServlet#initHandlerMappings
// 该属性可以web.xml中配置,默认为true
this.detectAllHandlerMappings
// 获取所有 HandlerMapping 接口的所有实现类
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
// HandlerMapping 的所有实现类注册到 handlerMappings 集合容器中
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
// 默认 handlerMappings 注册
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
org.springframework.web.servlet.DispatcherServlet#getDefaultStrategies
String value = defaultStrategies.getProperty(key);
defaultStrategies 属性在静态块中进行了初始化
private static final Properties defaultStrategies;
static {
try {
// DispatcherServlet.properties 配置文件,该配置文件对springMVC 做了初始化工作的配置
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
springmvc.xml 中配置
<!--DefaultAnnotationHandlerMapping已过时,改为
RequestMappingHandlerMapping-->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!--AnnotationMethodHandlerAdapter 已过时,改为
RequestMappingHandlerAdapter初始化 messageConverters 默认的消息转换器-->
<bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<!--消息转换器,在这里可以注册其它消息转换器-->
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter"/>
<ref bean="stringHttpMessageConverter"/>
</list>
</property>
</bean>
<!-- StringHttpMessageConverter 默认编码为 ISO-8859-1 -->
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain;charset=UTF-8"/>
</bean>
<!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
配置 MappingJackson2HttpMessageConverter 参考
这两个类在 DispatcherServlet.properties 配置文件中做了默认配置,所以在springMvc.xml中可以不用配置该bean
- DefaultAnnotationHandlerMapping
- AnnotationMethodHandlerAdapter
request 请求实际上会先走到 javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
方法中。
在spring mvc 中则查看 org.springframework.web.servlet.FrameworkServlet#service
方法
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) { //处理请求
processRequest(request, response);
}
org.springframework.web.servlet.FrameworkServlet#processRequest
doService(request, response);
spring mvc 请求流程
org.springframework.web.servlet.DispatcherServlet#doService
// 在 request 请求中存放相关信息
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
//重点,spring mvc 的请求与响应过程
doDispatch(request, response);
springmvc请求响应流程
@RequestMapping 标记的方法会封装为 HandlerMethod 对象
HandlerMapping 就是 url 与 HandlerMethod 的映射关系
HandlerAdapter 负责调用具体Controller中的方法,HandlerAdapter 可以解析请求的方法参数、方法的返回值解析。用策略模式解析
org.springframework.web.servlet.DispatcherServlet#doDispatch
mappedHandler = getHandler(processedRequest);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
org.springframework.web.servlet.DispatcherServlet#getHandler
// this.handlerMappings 容器在前面已经初始化过了,所以有值
for (HandlerMapping hm : this.handlerMappings) {
// 查看 getHandler 方法
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
Object handler = getHandlerInternal(request);
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
HandlerMethod handlerMethod =
lookupHandlerMethod(lookupPath, request);
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
获取到方法上的所有相关配置信息
/query-student = {[/query-student],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}
// 获取到方法上的所有相关配置信息
List<T> directPathMatches =
this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getMappings().keySet(),
matches, request);
}
这个容器是是在什么时候初始化的?
MappingRegistry#mappingLookup
this.mappingRegistry.getMappings().keySet()
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods
// 循环容器中的所有bean
for (String beanName : beanNames) {
// isHandler:过滤 @Controller,@RequestMapping 的bean
if (beanType != null && isHandler(beanType)) {
// beanName 就是 Controller 类的名称
detectHandlerMethods(beanName);
}
}
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods
// 当前 controller 类
final Class<?> userType = ClassUtils.getUserClass(handlerType);
// 查询当前controller 类所有 @RequestMapping 注解标记的方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
// 过滤 @RequestMapping 注解标记的方法
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
// 所有方法都注册到 MappingRegistry#mappingLookup 容器中
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
// 注册 HandlerMethod 逻辑
registerHandlerMethod(handler, invocableMethod, mapping);
}
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod
this.mappingRegistry.register(mapping, handler, method);
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register
// 往 MappingRegistry#mappingLookup 容器中注册信息
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 注册
this.urlLookup.add(url, mapping);
}
//跨域请求信息配置
CorsConfiguration corsConfig =
initCorsConfiguration(handler, method, mapping);
this.mappingLookup
key: RequestMappingInfo
value:HandlerMethod
key:{[/query-student],methods=[],params=[],
headers=[],consumes=[],produces=[],custom=[]}
value: public java.util.Map com.dn.spring.controller.HelloWorldController.student(
java.lang.Integer)
this.urlLookup
key: /query-student
value: {[/query-student],methods=[],params=[],
headers=[],consumes=[],produces=[],custom=[]}
先根据请求url,在 this.urlLookup 获取 value
再根据 value 在 this.mappingLookup 获取 HandlerMethod
这个逻辑体现在 AbstractHandlerMethodMapping#getHandlerInternal 方法中HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
返回到
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
// handler 其实就是 HandlerMethod
Object handler = getHandlerInternal(request);
// 将 HandlerMethod 和 拦截器集合 封装到 HandlerExecutionChain
HandlerExecutionChain executionChain =
getHandlerExecutionChain(handler, request);
返回到
org.springframework.web.servlet.DispatcherServlet#doDispatch
spring mvc 请求流程逻辑
// HandlerExecutionChain 中有 HandlerMethod 和 拦截器集合
mappedHandler = getHandler(processedRequest);
// 将 HandlerMethod 做为参数传入 getHandlerAdapter 方法
// 得到 RequestMappingHandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 拦截器 前置执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//(查看该方法)请求对应的方法调用
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 拦截器 中置执行
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 拦截器 后置执行
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
return handleInternal(request, response, (HandlerMethod) handler);
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
mav = invokeHandlerMethod(request, response, handlerMethod);
RequestMappingHandlerAdapter#afterPropertiesSet 这里做了一些初始化工作
- 默认的参数解析器集合初始化:argumentResolvers
- 参数绑定解析器集合初始化:initBinderArgumentResolvers
- 方法返回值解析器集合初始化:returnValueHandlers
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
invocableMethod.invokeAndHandle(webRequest, mavContainer);
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
// (查看该方法)请求方法执行的返回值
Object returnValue =
invokeForRequest(webRequest, mavContainer, providedArgs);
try {
// 方法返回值的类型转换处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue),
mavContainer, webRequest);
}
org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
// 解析请求方法的参数信息
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
//执行请求方法并得到方法的返回值
Object returnValue = doInvoke(args);
org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
MethodParameter[] parameters = getMethodParameters()
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
// 使用策略模式,得到当前参数的处理类
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
// 参数解析
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
}
}
@RequestBody 注解的参数解析
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
// 支持的注解
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
// 参数解析
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//解析
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
}
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#readWithMessageConverters
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(org.springframework.http.HttpInputMessage, org.springframework.core.MethodParameter, java.lang.reflect.Type)
//获取请求类型
contentType = inputMessage.getHeaders().getContentType();
// 循环消息转转换器
// RequestMappingHandlerAdapter的无参构造器中加载默认的 HttpMessageConverter 实现类
// 在 RequestMappingHandlerAdapter#afterPropertiesSet 方法中加载
// 默认参数解析器时,将 HttpMessageConverter 的所有实现类传入到
// RequestResponseBodyMethodProcessor 类的构造函数中,并传入到父类
// AbstractMessageConverterMethodArgumentResolver 中的属性messageConverters中
// 所以在这里可以获取到所有注册的消息转换器实现类
for (HttpMessageConverter<?> converter : this.messageConverters) {
//找到能处理该参数类型的消息转换器,会使用 StringHttpMessageConverter 类处理
if (converter.canRead(targetClass, contentType)) {
body =
((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
}
}
StringHttpMessageConverter 类
这里调用是父类中的方法 read
org.springframework.http.converter.AbstractHttpMessageConverter#read
@Override
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
return readInternal(clazz, inputMessage);
}
org.springframework.http.converter.StringHttpMessageConverter#readInternal
@Override
protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
// 读取输入流中的内容
return StreamUtils.copyToString(inputMessage.getBody(), charset);
}
入参 @RequestBody 参数解析,并没有使用json的消息转换器,而是使用了 StringHttpMessageConverter 消息转换器
返回到
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
//方法的返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue
//查看该方法,根据返回类型找到对应的处理器
HandlerMethodReturnValueHandler handler =
selectHandler(returnValue, returnType);
//返回值类型的转换处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#selectHandler
// this.returnValueHandlers 是在
// RequestMappingHandlerAdapter#afterPropertiesSet 方法中初始化的
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
返回到
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
-
查看 ViewNameMethodReturnValueHandler#handleReturnValue,当返回类型为字符串时,则返回到指定的页面
if (returnValue instanceof CharSequence) { String viewName = returnValue.toString(); mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } }
-
查看 RequestResponseBodyMethodProcessor#handleReturnValue,当返回值有 @RequestBody 注解时,则不会返回页面
//这里设置的值很重要 mavContainer.setRequestHandled(true);
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)
for (HttpMessageConverter<?> messageConverter : this.messageConverters) { ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage); }
返回json 消息转换器 MappingJackson2HttpMessageConverter,
查看 AbstractHttpMessageConverter#write方法 调用的是父类的
org.springframework.http.converter.AbstractGenericHttpMessageConverter#write 方法writeInternal(t, outputMessage);
org.springframework.http.converter.AbstractGenericHttpMessageConverter#writeInternal(T, org.springframework.http.HttpOutputMessage)
writeInternal(t, null, outputMessage);
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding); // 将返回值转换为json格式 objectWriter.writeValue(generator, value);
返回到
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//查看该方法
return getModelAndView(mavContainer, modelFactory, webRequest);
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelAndView
//可以看到为true时,则结束了,这里的值来自:RequestResponseBodyMethodProcessor#handleReturnValue 方法中的设置
// 不走视图模式
if (mavContainer.isRequestHandled()) {
return null;
}
//走视图模式
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
返回到
org.springframework.web.servlet.DispatcherServlet#doDispatch
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
org.springframework.web.servlet.DispatcherServlet#processDispatchResult
render(mv, request, response);
org.springframework.web.servlet.DispatcherServlet#render
// 找到视图解析器
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
// 查看 InternalResourceView类
view.render(mv.getModelInternal(), request, response);
org.springframework.web.servlet.DispatcherServlet#resolveViewName
for (ViewResolver viewResolver : this.viewResolvers) {
// 找到视图解析器
View view = viewResolver.resolveViewName(viewName, locale);
}
InternalResourceView#render 调用的是父类的方法
org.springframework.web.servlet.view.AbstractView#render
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel
// 请求页面的路径
String dispatcherPath = prepareForRendering(request, response);
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
// 调用转到页面的方法
rd.forward(request, response);
forward 、include、Rediect 参考
总结
- spring mvc 初始化工作
- spring mvc 请求与响应流程
- spring mvc 入参解析
- spring mvc 出参解析
- spring mvc 视图解析