- 浏览: 236625 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
shuhucy:
必须赞啊,源码理解的很深,解决一个困扰两天的问题
Spring AOP源码分析(八)SpringAOP要注意的地方 -
sealinesu:
精彩
Spring事务源码分析(一)Spring事务入门 -
whlt20090509:
"WEB-INF/view目录下有一个简单的hell ...
SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门 -
hai0378:
兄台 算我一个,最近在研究dubbo motan 及 zk ...
ZooKeeper源码研究寻求小伙伴 -
zpkbtzmbw:
看懂了,原理
SpringMVC源码总结(五)Tomcat的URIEncoding、useBodyEncodingForURI和CharacterEncodingFilter
SpringMVC源码总结(六)mvc:annotation-driven中的HandlerMethodReturnValueHandler
- 博客分类:
- SpringMVC源码分析
经过了两篇的乱码说明,要重新回到mvc:annotation-driven标签中,继续说说HandlerMethodReturnValueHandler的使用,下一篇文章主要说说HttpMessageConverter。
HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用来处理当含有@RequestMapping的方法调度完成后,后面要进行的事情。
首先是HandlerMethodReturnValueHandler的自定义注册:
mvc:annotation-driven配置如下:
在启动AnnotationDrivenBeanDefinitionParser来解析mvc:annotation-driven标签的过程中(见本系列第三篇博客),会注册我们所配置的HandlerMethodReturnValueHandler,如下:
然后将会这些自定义的HandlerMethodReturnValueHandler设置到RequestMappingHandlerAdapter的customReturnValueHandlers属性中,
RequestMappingHandlerAdapter的两个重要属性:
customReturnValueHandlers:存放我们自定义的HandlerMethodReturnValueHandler;
returnValueHandlers:存放最终所有的HandlerMethodReturnValueHandler;
如下所示:
returnValueHandlers的属性类型为HandlerMethodReturnValueHandlerComposite,里面也有一个list集合,来存放所有的HandlerMethodReturnValueHandler。
HandlerMethodReturnValueHandlerComposite结构如下:
在RequestMappingHandlerAdapter创建出来后,会执行afterPropertiesSet()方法,在该方法中会设置所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers属性中如下:
getDefaultReturnValueHandlers()方法会获取默认要注册的和我们自定义的HandlerMethodReturnValueHandler,如下:
至此,所有的HandlerMethodReturnValueHandler的注册已经完成。我们可以再回顾下,在该系列的第三篇博客中介绍HandlerMethodReturnValueHandler的使用。
第一步:获取合适的HandlerAdapter,当方法含有@RequestMaiing注释的时候,便选择RequestMappingHandlerAdapter来进行方法的调度处理
第二步:方法的调度处理过程为:首先执行方法体,然后根据返回值来选择一个合适的HandlerMethodReturnValueHandler,如下代码:
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest)会遍历所有的已注册的HandlerMethodReturnValueHandler判断他们支不支持returnValue的返回类型。如下:
找到支持的HandlerMethodReturnValueHandler后,就要执行它的handleReturnValue方法。
下面就具体介绍下下常用的这几个HandlerMethodReturnValueHandler;
HttpEntityMethodProcessor:用来处理返回值类型是HttpEntity的方法,简单用法如下
就是在构建http协议的返回体和返回头。
使用案例如,文件下载。
经常有人直接用HttpServletRequest和HttpServletResponse来做文件下载,这种方式便与web容器产生的对象耦合在一起,不推荐使用,而是直接使用spring为我们提供的HttpEntityMethodProcessor这一返回值处理器,虽然springmvc最终还是用HttpServletResponse来实现,但是这种方式便断开我们直接与web容器之间的耦合。
这一过程分析:
当这个方法执行完成之后,会调用HttpEntityMethodProcessor的handleReturnValue方法,
该方法内容就是为response设置响应头,然后将响应体的内容写入response的body中,此时又会涉及到HttpMessageConverter,当HttpEntity中的body类型为String,又会让StringHttpMessageConverter来进行转换。这和@ResponseBody的处理过程是一样的。
ViewNameMethodReturnValueHandler:主要用来处理返回值是String类型(前提不含@ResponseBody标签),它会将返回的字符串作为view视图的名字,如下所示。
另一种用法,当返回的字符串以redirect:开始,不再作为view视图名而是作为重定向的地址,如下:
有了重定向,也有转发。以forward:开头便是转发。
如下:
ModelMethodProcessor:用来处理返回类型为Model的,它默认采用请求路径作为视图名称,如下:
ModelAndViewMethodReturnValueHandler:用来处理返回值类型为ModelAndView,如下:
RequestResponseBodyMethodProcessor:则是用于处理方法中含有@ResponseBody注解,或类上含有@ResponseBody注解。这一处理过程在本系列的第三篇博客中有介绍,这里不再叙述。
还有其他的HandlerMethodReturnValueHandler,这里仅仅是作为引路,对HandlerMethodReturnValueHandler有个整体的认识,具体的内容,需要读者去具体研究。
HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用来处理当含有@RequestMapping的方法调度完成后,后面要进行的事情。
首先是HandlerMethodReturnValueHandler的自定义注册:
mvc:annotation-driven配置如下:
<mvc:annotation-driven> <mvc:return-value-handlers> <bean class="org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler"></bean> </mvc:return-value-handlers> </mvc:annotation-driven>
在启动AnnotationDrivenBeanDefinitionParser来解析mvc:annotation-driven标签的过程中(见本系列第三篇博客),会注册我们所配置的HandlerMethodReturnValueHandler,如下:
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
private ManagedList<?> getReturnValueHandlers(Element element, ParserContext parserContext) { Element handlersElement = DomUtils.getChildElementByTagName(element, "return-value-handlers"); if (handlersElement != null) { return extractBeanSubElements(handlersElement, parserContext); } return null; }
然后将会这些自定义的HandlerMethodReturnValueHandler设置到RequestMappingHandlerAdapter的customReturnValueHandlers属性中,
RequestMappingHandlerAdapter的两个重要属性:
customReturnValueHandlers:存放我们自定义的HandlerMethodReturnValueHandler;
returnValueHandlers:存放最终所有的HandlerMethodReturnValueHandler;
如下所示:
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { private List<HandlerMethodArgumentResolver> customArgumentResolvers; private HandlerMethodArgumentResolverComposite argumentResolvers; private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers; //这里这里这里这里这里这里这里这里 private List<HandlerMethodReturnValueHandler> customReturnValueHandlers; //这里这里这里这里这里这里这里这里 private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
returnValueHandlers的属性类型为HandlerMethodReturnValueHandlerComposite,里面也有一个list集合,来存放所有的HandlerMethodReturnValueHandler。
HandlerMethodReturnValueHandlerComposite结构如下:
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler { protected final Log logger = LogFactory.getLog(getClass()); private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<HandlerMethodReturnValueHandler>(); /**
在RequestMappingHandlerAdapter创建出来后,会执行afterPropertiesSet()方法,在该方法中会设置所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers属性中如下:
@Override public void afterPropertiesSet() { 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) { //获取所有的HandlerMethodReturnValueHandler List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } initControllerAdviceCache(); }
getDefaultReturnValueHandlers()方法会获取默认要注册的和我们自定义的HandlerMethodReturnValueHandler,如下:
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>(); // Single-purpose return value types handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager)); handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); // Annotation-based return value types handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager)); // Multi-purpose return value types handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); // Custom return value types //这里这里会从customReturnValueHandlers属性中获取我们自定的HandlerMethodReturnValueHandler if (getCustomReturnValueHandlers() != null) { handlers.addAll(getCustomReturnValueHandlers()); } // Catch-all if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers())); } else { handlers.add(new ModelAttributeMethodProcessor(true)); } return handlers; }
至此,所有的HandlerMethodReturnValueHandler的注册已经完成。我们可以再回顾下,在该系列的第三篇博客中介绍HandlerMethodReturnValueHandler的使用。
第一步:获取合适的HandlerAdapter,当方法含有@RequestMaiing注释的时候,便选择RequestMappingHandlerAdapter来进行方法的调度处理
第二步:方法的调度处理过程为:首先执行方法体,然后根据返回值来选择一个合适的HandlerMethodReturnValueHandler,如下代码:
public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); //重点重点重点重点重点重点重点重点重点重点 try { this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest)会遍历所有的已注册的HandlerMethodReturnValueHandler判断他们支不支持returnValue的返回类型。如下:
public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]"); handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } /** * Find a registered {@link HandlerMethodReturnValueHandler} that supports the given return type. */ private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) { for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) { if (logger.isTraceEnabled()) { logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" + returnType.getGenericParameterType() + "]"); } if (returnValueHandler.supportsReturnType(returnType)) { return returnValueHandler; } } return null; }
找到支持的HandlerMethodReturnValueHandler后,就要执行它的handleReturnValue方法。
下面就具体介绍下下常用的这几个HandlerMethodReturnValueHandler;
HttpEntityMethodProcessor:用来处理返回值类型是HttpEntity的方法,简单用法如下
@RequestMapping(value="/test/httpEntity",method=RequestMethod.GET) public HttpEntity<String> testHttpEntity() throws UnsupportedEncodingException{ String body="中国"; HttpHeaders headers=new HttpHeaders(); headers.add("Content-type","text/html;charset=GBK"); HttpEntity<String> ret=new HttpEntity<String>(body,headers); return ret; }
就是在构建http协议的返回体和返回头。
使用案例如,文件下载。
经常有人直接用HttpServletRequest和HttpServletResponse来做文件下载,这种方式便与web容器产生的对象耦合在一起,不推荐使用,而是直接使用spring为我们提供的HttpEntityMethodProcessor这一返回值处理器,虽然springmvc最终还是用HttpServletResponse来实现,但是这种方式便断开我们直接与web容器之间的耦合。
这一过程分析:
当这个方法执行完成之后,会调用HttpEntityMethodProcessor的handleReturnValue方法,
该方法内容就是为response设置响应头,然后将响应体的内容写入response的body中,此时又会涉及到HttpMessageConverter,当HttpEntity中的body类型为String,又会让StringHttpMessageConverter来进行转换。这和@ResponseBody的处理过程是一样的。
ViewNameMethodReturnValueHandler:主要用来处理返回值是String类型(前提不含@ResponseBody标签),它会将返回的字符串作为view视图的名字,如下所示。
另一种用法,当返回的字符串以redirect:开始,不再作为view视图名而是作为重定向的地址,如下:
@RequestMapping(value="/test/string",method=RequestMethod.GET) public String testString(){ return "redirect:/string"; }
有了重定向,也有转发。以forward:开头便是转发。
如下:
@RequestMapping(value="/test/string",method=RequestMethod.GET) public String testString(){ return "forward:/string"; }
ModelMethodProcessor:用来处理返回类型为Model的,它默认采用请求路径作为视图名称,如下:
@RequestMapping(value="/test/model",method=RequestMethod.GET) public Model handleModel(String name) throws Exception { Model model=new ExtendedModelMap(); model.addAttribute("name",name); return model; }
ModelAndViewMethodReturnValueHandler:用来处理返回值类型为ModelAndView,如下:
@RequestMapping(value="/test/modelandview",method=RequestMethod.GET) public ModelAndView testModelAndView() throws Exception { return new ModelAndView("hello"); }
RequestResponseBodyMethodProcessor:则是用于处理方法中含有@ResponseBody注解,或类上含有@ResponseBody注解。这一处理过程在本系列的第三篇博客中有介绍,这里不再叙述。
还有其他的HandlerMethodReturnValueHandler,这里仅仅是作为引路,对HandlerMethodReturnValueHandler有个整体的认识,具体的内容,需要读者去具体研究。
发表评论
-
SpringMVC源码总结(十二)ViewResolver介绍
2014-09-10 06:43 2263首先我们先看看ModelAndView中重要的View接口。 ... -
SpringMVC源码总结(十一)mvc:interceptors拦截器介绍
2014-09-08 20:21 5781本文章针对mvc:interceptors标签进行介绍,它的注 ... -
SpringMVC源码总结(十)自定义HandlerMethodArgumentResolver
2014-09-04 07:45 7368上一篇文章介绍了HandlerMethodArgumentRe ... -
SpringMVC源码总结(九)HandlerMethodArgumentResolver介绍
2014-09-02 06:24 12390本文章主要介绍HandlerMethodArgumentRes ... -
SpringMVC源码总结(八)类型转换PropertyEditor的背后
2014-08-30 17:13 4836PropertyEditor是Spring最初 ... -
SpringMVC源码总结(七)mvc:annotation-driven中的HttpMessageConverter
2014-08-27 22:32 6570这一篇文章主要介绍下HttpMessageConverter整 ... -
SpringMVC源码总结(五)Tomcat的URIEncoding、useBodyEncodingForURI和CharacterEncodingFilter
2014-08-22 06:32 7330继续上一章节的乱码问题。上一篇文章仅仅说了设置Tomcat的U ... -
SpringMVC源码总结(四)由StringHttpMessageConverter引出的客户端服务器端之间的乱码过程分析
2014-08-20 22:49 3629继续上一篇文章遗留的乱码问题,引出从客户端数据到服务器端的乱码 ... -
SpringMVC源码总结(三)mvc:annotation-driven和mvc:message-converters简单介绍
2014-08-19 06:58 10124上一篇文章讲述了最简单的mvc:annotation-driv ... -
SpringMVC源码总结(二)mvc:annotation-driven以及@Controller和@RequestMapping的那些事
2014-08-16 22:47 8631上一篇文章让我们了解HandlerMapping和Handle ... -
SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
2014-08-16 22:42 14694刚接触SpringMVC,对它的xml文件配置一直比较模模糊糊 ...
相关推荐
在Spring MVC框架中,`mvc:annotation-driven`和`mvc:message-converters`是两个非常重要的元素,它们在处理基于注解的控制器和数据转换方面起着关键作用。本篇文章将深入探讨这两个组件的工作原理以及如何在实际...
在Spring MVC框架中,`mvc:annotation-driven`是Spring MVC配置中的一个重要元素,它使得我们的应用能够支持基于注解的控制器、数据绑定、格式化转换器和服务端验证等功能。这篇博客将深入探讨`mvc:annotation-...
深入源码分析,`<mvc:annotation-driven />` 是Spring MVC中用于启用注解驱动的配置元素,它会自动配置一些关键组件,包括消息转换器。`MvcNamespaceHandler` 是处理这个注解的命名空间处理器,而`...
标题中的“一个简单的springMVC项目的配置文件”指的是基于Spring MVC框架构建的Web应用程序的配置文件,这通常包括XML配置、Java配置或者两者的结合。Spring MVC是Spring框架的一个模块,用于处理Web请求和响应,它...
`mvc:annotation-driven`则是开启Spring MVC的注解驱动,支持我们在Controller方法上使用@RequestMapping等注解。 除了基本配置,我们还可以配置拦截器(Interceptor)、异常处理器(HandlerExceptionResolver)...
SSM(Spring、SpringMVC、MyBatis)框架是Java Web开发中常见的技术栈,它结合了Spring的IOC(Inversion of Control)容器、SpringMVC作为控制器以及MyBatis作为持久层框架,提供了强大的功能和灵活性。在这个示例中...
<mvc:annotation-driven/> <!-- 视图解析器配置 --> <property name="prefix" value="/WEB-INF/views/" /> ``` 然后,创建一个简单的Controller类,使用注解来处理HTTP请求。例如,一个处理GET请求的...
</mvc:annotation-driven> ``` 3. **控制器中的编码配置**:还可以在控制器方法中显式指定返回数据的编码。 ```java @RequestMapping(value="/getWeather", method={RequestMethod.POST, RequestMethod.GET}, ...
在本文中,我们将深入探讨如何在Eclipse集成开发环境中配置SpringMVC的源码,以便进行深入学习和开发。SpringMVC是Spring框架的一部分,它为构建基于Java的Web应用程序提供了一个模型-视图-控制器(MVC)架构。...
在本文中,我们将深入探讨如何在Spring 3.0中整合MVC框架与RESTful服务,并结合Maven构建项目。RESTful(Representational State Transfer)是一种软件架构风格,用于设计网络应用程序,尤其适用于Web服务。Spring ...
<mvc:annotation-driven/> <property name="prefix" value="/WEB-INF/views/"/> ``` 4. **创建 Controller** 创建一个名为 `HelloController` 的 Java 类,使用 `@Controller` 注解标记为 MVC 控制器,...
在applicationContext.xml中配置了<context:component-scan base-package="..." />,这个配置是扫描整个项目的包,而在applicationContext-MVC.xml中配置了<mvc:annotation-driven />,这个配置是扫描SpringMVC的...
<mvc:annotation-driven /> <context:component-scan base-package="com.example.springmvc"/> ``` 接着,创建Controller类。使用@Controller注解标记该类为SpringMVC的控制器,并通过@RequestMapping注解来映射URL...
<mvc:annotation-driven /> <property name="prefix" value="/WEB-INF/views/" /> ``` 这里,`base-package`属性指定你的控制器类所在的包,`InternalResourceViewResolver`则配置了视图解析规则。 5. **...
14. **MVC注解驱动**:通过启用`@EnableWebMvc`或在配置文件中设置`<mvc:annotation-driven>`,可以启用SpringMVC的注解驱动,简化配置。 15. **SpringMVC与其他Spring组件的集成**:如与Spring AOP结合实现切面...
<mvc:annotation-driven /> <property name="prefix" value="/WEB-INF/views/" /> ``` #### 3. `applicationContext.xml` 这是 Spring 容器的配置文件,用于配置业务对象和服务: ```xml ...
1. **配置RESTful支持**:在SpringMVC的配置文件中启用`<mvc:annotation-driven>`元素,以支持@RequestMapping等注解。 2. **控制器(Controllers)**:使用@Controller和@RequestMapping注解定义处理HTTP请求的...
<mvc:annotation-driven/> ``` - 如果使用 Spring Boot,配置可以简化为自动扫描控制器和启用 MVC 功能。 5. **编写控制器** - 创建 Java 类,如 `HelloController.java`,并添加 `@RestController` 或 `@...
<mvc:annotation-driven/> <property name="prefix" value="/WEB-INF/views/"/> ``` 配置扫描包、启用注解驱动以及设置视图解析器。 4. **index.jsp**:显示结果的JSP页面。 ```jsp ; charset=UTF-...