spring自定义HandlerMethodReturnValueHandler和HandlerMethodArgumentResolver但不能指定解析顺序的问题

问题描述

如果要添加自定义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实例注入时出现循环依赖错误。
测试可用,有更好的解决办法的话留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值