在springmvc中,经常用到自定义的入参解析器和返回参数解析器。
使用方式如下,在spring容器中配置:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="xx.xx.JsonMapperArgumentResolver"/>
</mvc:argument-resolvers>
<mvc:return-value-handlers>
<bean class="xx.xx.ResponseJsonMethodProcessor">
<property name="messageConverter">
<bean class="xx.xx.Base64JsonHttpMessageConverter"/>
</property>
<property name="beanWrappers">
<list>
<bean class="xx.xx.ResponseWrapper"/>
<bean class="xx.xx.DefaultBeanWrapper"/>
</list>
</property>
</bean>
</mvc:return-value-handlers>
</mvc:annotation-driven>
上面这段配置中,定义了入参解析器JsonMapperArgumentResolver,定义了返回参数解析器ResponseJsonMethodProcessor,返回参数解析器中注入了messageConverter和beanWrapper。
入参解析器需要继承HandlerMethodArgumentResolver接口,实现supportsParameter方法和resolveArgument方法。supportsParameter方法表明该解析器支持的参数类型,通常是通过返回布尔值:parameter.hasParameterAnnotation(自定义注解.class)来表明支持参数上有自定义注解如@Json的入参。resolveArgument则负责对参数进行解析,将其绑定到领域模型model上。
出参解析器需要继承HandlerMethodReturnValueHandler接口,实现supportsReturnType方法和handleReturnValue方法。同样前者表明支持的返回参数类型,handleReturnValue则对返回参数进行处理。
入参解析器和出参解析器是在RequestMappingHanlderAdapter中初始化的。RequestMappingHanlderAdapter部分源码如下:
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean
{
//待bean属性初始化完,初始化一些ArgumentResolvers
public void afterPropertiesSet()
{
if(argumentResolvers == null)
{
List resolvers = getDefaultArgumentResolvers();
argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(resolvers);
}
if(initBinderArgumentResolvers == null)
{
List resolvers = getDefaultInitBinderArgumentResolvers();
initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(resolvers);
}
if(returnValueHandlers == null)
{
List handlers = getDefaultReturnValueHandlers();
returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
}
…
可以看到,afterPropertiesSet方法中对请求参数解析器和返回参数解析器进行初始化。
当在spring容器中配置<mvc:annotation-driven>
元素时,这里参数处理器会初始化一次。此时如果配置了自定义返回参数处理器,就会注册到ReturnValueHandles中去。如果在spring子容器,也就是dispatchServlet容器中再次配置一个默认的<mvc:annotation-driven/>
表示使用默认值,这时会再一次调用afterPropertiesSet对returnValueHandlers 进行初始化,此时新的returnValueHandlers 就覆盖掉了原来的含自定义处理器的returnValueHandlers ,导致注册失败。
当初始化没有问题时,接着在doDispatcher中的相应处理方法中,选择合适的返回参数解析器进行处理。选择的标准就是判断返回的类型retureType是否是支持的返回参数类型。
总结:如果在调试中发现自定义的参数解析器根本就没有进入,可以按照上面的思路进行分析。先看是否正常初始化,是不是在父容器和子容器中定义了互相矛盾的处理适配器策略。然后再看自定义参数解析器中支持的注解类型和实际方法上注解的类型是否一致。
这两种情况都实际遇到过,前者是子容器中配置了<mvc:annotation-driven/>
导致初始化时自定义的参数解析器被覆盖;第二种情况是返回的方法上的注解和自定义参数解析器中支持的注解类型不在同一个包。