问题描述
如果要添加自定义Handler, 可以写一个配置类,添加Configuration注解,并实现WebMvcConfigurer接口,通过addReturnValueHandlers()和addArgumentResolvers()方法注入自定义的HandlerMethodReturnValueHandler和HandlerMethodArgumentResolver
@Configuration
public class MyConfiguration implements WebMvcConfigurer{
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
MyArgumentResolver myArgumentResolver
= new MyArgumentResolver ();
resolvers.add(0, myArgumentResolver);
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
MyReturnValueHandler myReturnValueHandler
= new MyReturnValueHandler();
handlers.add(0, myReturnValueHandler);
}
}
但是这样添加的注解并不能够像字面上描述的那样将自定义的解析器放到最前面执行。
spring在加载时,通过RequestMappingHandlerAdapter类的afterPropertiesSet加载默认的解析器
@Override
public void afterPropertiesSet() {
....//省略前面的代码
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
真正起作用的是这里的getDefaultReturnValueHandlers方法
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
...//提前添加了14个默认的解析器,不能调整顺序,省略这些代码
// 添加自定义的解析器
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
..//省略部分代码
return handlers;
}
可以看到,自定义的解析器是被添加到14位以后的。所以并不能通过这种方式实现上述的需求。
一种解决方案
修改Configuration类,使其不再继承WebMvcConfigurer接口,同时删除相关的重载方法,同时注入RequestMappingHandlerAdapter对象,在@PostConstruct注解的方法中,直接操作该对象,重新设置Handler
@Configuration
public class MyConfiguration{
@Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
/**
* 注册自定义的返回值处理器和参数解析器
* 不能使用WebMvcConfigurer,重载addArgumentResolvers和addReturnValueHandlers方法实现
* 因为这样不能将自定义的解析器放到最前面,导致Map等对象的解析被默认解析器拦截,导致运行出错
* 注意,这里不能再继承 WebMvcConfigurer,否则会导致RequestMappingHandlerAdapter实例注入时出现循环依赖错误
*/
@PostConstruct
public void init() {
//注入自定义的ReturnValueHandler
final List<HandlerMethodReturnValueHandler> defaultReturnValueHandlers = requestMappingHandlerAdapter.getReturnValueHandlers();
//必须要新建一个List,不能直接通过defaultReturnValueHandlers赋值,因为原来的List是只读的,无法写入
List<HandlerMethodReturnValueHandler> myReturnValueHandlers = new ArrayList<>();
myReturnValueHandlers.add(new MyReturnValueHandler());
myReturnValueHandlers.addAll(defaultReturnValueHandlers);
requestMappingHandlerAdapter.setReturnValueHandlers(myReturnValueHandlers);
//注入自定义的ArgumentResolver
final List<HandlerMethodArgumentResolver> defaultArgumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();
//必须要新建一个List,不能直接通过defaultArgumentResolvers赋值,因为原来的List是只读的,无法写入
List<HandlerMethodArgumentResolver> myArgumentResolvers = new ArrayList<>();
myArgumentResolvers.add(new MyArgumentResolver());
myArgumentResolvers.addAll(defaultArgumentResolvers);
requestMappingHandlerAdapter.setArgumentResolvers(myArgumentResolvers);
}
}
注意,该配置类不能再继承 WebMvcConfigurer,否则会导致RequestMappingHandlerAdapter实例注入时出现循环依赖错误。
测试可用,有更好的解决办法的话留言讨论。