Skip to content

Commit 270c7be

Browse files
committed
1 parent 88ceee2 commit 270c7be

File tree

3 files changed

+368
-3
lines changed

3 files changed

+368
-3
lines changed
40.1 KB
Loading

note/spring-mvc.md

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ initFlashMapManager方法会向容器注册SessionFlashMapManager对象,类图
423423
protected void initHandlerMethods() {
424424
//获取容器中所有的bean
425425
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
426-
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :getApplicationContext().getBeanNamesForType(Object.class));
426+
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :getApplicationContext().getBeanNamesForType(Object.class));
427427
for (String beanName : beanNames) {
428428
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
429429
Class<?> beanType = null;
@@ -960,3 +960,101 @@ protected void renderMergedOutputModel(
960960

961961
可以看出,对jsp来说,所谓的渲染其实就是**将Model中的属性设置到Request,再利用原生Servlet RequestDispatcher API进行转发的过程**
962962

963+
# 拾遗
964+
965+
## @ResponseBody
966+
967+
通常我们可以在Controller或方法上标注@ResponseBody注解以表示需要将对象转为JSON并返回给前端,那么Spring MVC是如何自动完成这一过程的呢?
968+
969+
从前面初始化-容器初始化-容器创建-配置解析一节可以看出,Spring MVC采用org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser进行配置的解析,核心的parse方法中完成了对HttpMessageConverter的初始化。
970+
971+
### HttpMessageConverter
972+
973+
Spring的HttpMessageConverter接口负责HTTP请求-Java对象与Java对象-响应之间的转换。我们以Spring默认使用的Jackson转换器为例,类图:
974+
975+
![HttpMessageConverter](images/HttpMessageConverter.jpg)
976+
977+
HttpMessageConverter实现的初始化由AnnotationDrivenBeanDefinitionParser的getMessageConverters方法完成,HttpMessageConverter的来源分为自定义和默认。
978+
979+
示例配置:
980+
981+
```xml
982+
<mvc:annotation-driven>
983+
<mvc:message-converters register-defaults="true">
984+
<bean class="test.Converter" />
985+
</mvc:message-converters>
986+
</mvc:annotation-driven>
987+
```
988+
989+
#### 自定义
990+
991+
Spring允许我们通过XML配置文件的message-converters元素来进行自定义。
992+
993+
#### 默认
994+
995+
**检测到没有配置message-converters元素或者register-defaults="true"时Spring便会注册默认转换器**。这其中便包括MappingJacksonHttpMessageConverter,相关源码:
996+
997+
```java
998+
else if (jacksonPresent) {
999+
messageConverters.add(createConverterDefinition(
1000+
org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.class, source));
1001+
}
1002+
```
1003+
1004+
jacksonPresent声明:
1005+
1006+
```java
1007+
private static final boolean jacksonPresent =
1008+
ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) &&
1009+
ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
1010+
```
1011+
1012+
### 转换
1013+
1014+
入口位于ServletInvocableHandlerMethod的invokeAndHandle方法对于响应的处理:
1015+
1016+
```java
1017+
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
1018+
```
1019+
1020+
returnValueHandlers其实就是RequestMappingHandlerAdapter内部的returnValueHandlers,后者由RequestMappingHandlerAdapter的afterPropertiesSet方法初始化,关键在于:
1021+
1022+
```java
1023+
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
1024+
```
1025+
1026+
对象到JSON的转换正是由RequestResponseBodyMethodProcessor完成,ServletInvocableHandlerMethod通过supportsReturnType方法决定HandlerMethodReturnValueHandler是否可以处理当前返回类型或返回方法,RequestResponseBodyMethodProcessor的实现:
1027+
1028+
```java
1029+
@Override
1030+
public boolean supportsReturnType(MethodParameter returnType) {
1031+
return ((AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null) ||
1032+
(returnType.getMethodAnnotation(ResponseBody.class) != null));
1033+
}
1034+
```
1035+
1036+
核心的handleReturnValue方法:
1037+
1038+
```java
1039+
@Override
1040+
public void handleReturnValue(Object returnValue, MethodParameter returnType,
1041+
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
1042+
mavContainer.setRequestHandled(true);
1043+
if (returnValue != null) {
1044+
writeWithMessageConverters(returnValue, returnType, webRequest);
1045+
}
1046+
}
1047+
```
1048+
1049+
这里其实是通过HttpMessageConverter的canRead或canWrite方法来判断给定的转换器是否合适,canWrite方法实现:
1050+
1051+
```java
1052+
@Override
1053+
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
1054+
return (this.objectMapper.canSerialize(clazz) && canWrite(mediaType));
1055+
}
1056+
```
1057+
1058+
这里剩下的便是Jackson的事情了,注意MappingJacksonHttpMessageConverter中的objectMapper被所有的线程所共享,因为其是线程安全的,但是这样是否有性能问题?
1059+
1060+
//TODO HandlerMethodReturnValueHandler是神马?

0 commit comments

Comments
 (0)