Spring Mvc的参数注入分析

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2014/10/30/spring-mvc-argument-resolver/

Spring Mvc的一个强大之处在于对于各种参数注入的支持。

除了基本的request,session等等以外,还支持RequestParam等等便利的东西。基本而言使用Spring mvc你可以直接在方法中指明你希望获得的参数,让Spring注入即可。

参数注入的原理

Spring Mvc中有一个HandlerMethodArgumentResolver接口,其中包含两个方法:

publicbooleansupportsParameter(MethodParameter parameter)
publicObject (MethodParameter parameter,ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory)throws Exception

当请求被Spring Mvc处理并获取到对应的执行方法时,它会首先检查所需的所有参数,然后依次检查现有的HandlerMethodArgumentResolver等否支持此类型,如果可以再调用resolveArgument方法获取参数对象。

Spring Mvc自身有RequestParamMethodArgumentResolver,RequestParamMapMethodArgumentResolver等等常用的参数解析器。

在RequestMappingHandlerAdapter中的getDefaultArgumentResolvers方法中硬编码了它们,而且顺序是固定无法改变的。

Cookie的注入

只要实现了HandlerMethodArgumentResolver就可以实现参数注入,以Spring Mvc自带的ServletCookieValueMethodArgumentResolver。

因为从request从取出cookie值本身是一件相对简单的事情,所以这个类是一个很好的学习的例子。

@Overrideprotected ObjectresolveName(String cookieName, MethodParameter parameter, NativeWebRequest webRequest)throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName);
if (Cookie.class.isAssignableFrom(parameter.getParameterType())) {
return cookieValue;
}elseif (cookieValue !=null) {
returnthis.urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue());
}else {
returnnull;
}
}

`

直接获取到webRequest,从中取出所需的值即可。

自定义参数注入器

Spring Mvc提供了很多常见的支持,但是有时候有一些特殊的需求,需要我们自己定义。

首先创建一个对应的实现,实现supportsParameterresolveArgument

然后将这个类配置起来

<mvc:annotation-driven>
<mvc:argument-resolvers>
<beans:bean class="your resolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>

这里有个问题需要注意,那就是RequestMappingHandlerAdapter中已有的参数注入器的顺序是硬编码的,而自定义的部分在最后,所以要注意自定义的注入器不会和被Spring Mvc自带的部分解析掉。

private List < HandlerMethodArgumentResolver >getDefaultArgumentResolvers() {
List < HandlerMethodArgumentResolver > resolvers =new ArrayList < HandlerMethodArgumentResolver > ();

resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(),false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

if (getCustomArgumentResolvers() !=null) {
resolvers.addAll(getCustomArgumentResolvers());
}

resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(),true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));

return resolvers;
}

参考资料

Spring 3.1+ argument resolver cannot handle proprietary Person class argument

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2014/10/30/spring-mvc-argument-resolver/

《Spring Mvc的参数注入分析》有2条评论

    • 默认情况下Spring自带的参数注入器的优先级高于自定义的,理想情况下不应该让自定义的注入器和Spring自带的有冲突。
      简单办法是自定义一个新的类,这样就只有自定义的注入器能够支持。

      还有一种方法就是替换掉注入器的列表,将Spring自带的优先级降低。

      回复

回复 htynkn 取消回复