SpingBoot调用流程源码(二)入参出参映射类ArgumentResolver和ReturnValueHandler


在我们写代码的时候有时候需要做入参,出参映射,如果你们公司的网关已经实现了这个功能,那再好不过,如果没有,需要你在自己的某个服务中自己通过代码实现,这个时候Spring中的ArgumentResolver和ReturnValue类,就派上了用场。

一、ArgumentResolver源码分析

我们一个看看在Spring中,一个请求过来的时候什么时候使用到了ArgumentResolver。
在spring-boot中,默认情况下,当一个请求进来的时候,先进入DispatcherServlet,然后在handle方法中进入了RequestMappingHandlerAdapter的invokeHandlerMethod方法,一直下去会进入了InvocableHandlerMethod的getMethodArgumentValues方法,其中有这样一段:

args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);

如果你再参数前面加入了@RequestBody,就会进入RequestResponseBodyMethodProcessor的resolveArgument方法。
其时序图如下:

DispatcherSevlet RequestMappingHandlerAdapter ServletInvocableHandlerMethod InvocableHandlerMethod HandlerMethodArgumentResolverComposite RequestResponseBodyMethodProcessor doDispatcher() handle() invokeAndHandle() invokeForRequest() resolveArgument() resolveArgument() DispatcherSevlet RequestMappingHandlerAdapter ServletInvocableHandlerMethod InvocableHandlerMethod HandlerMethodArgumentResolverComposite RequestResponseBodyMethodProcessor

ReturnValueHandler是在返回的时候渲染的。不做过多解析了就。

二、注册时候的注意事项

如果你注册ArgumentResolver或ReturnValueHandler的时候像下面这样:

//    @Bean
//    public WebMvcConfigurer corsConfigurer() {
//        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry){
                registry.addInterceptor(new InPramMappingInterceptor())
                        .addPathPatterns("/**");
            }
//
            @Override
            public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
                List<HandlerMethodArgumentResolver> adapterArgumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();
                System.out.println(adapterArgumentResolvers.size());
//                resolvers.add(new RequestResponseBodySkinDTOMethodProcessor());
            }
//
//
//            @Override
//            public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers){
//            }
//        };
//    }

你会发现有时候执行不到你的ArgumentResolver,这是因为被别的拦截了,你需要像如下这样注册,才可以生效:

    @Resource
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @PostConstruct
    public void init() {
        final List<HandlerMethodReturnValueHandler> originalHandlers = new ArrayList<>(requestMappingHandlerAdapter.getReturnValueHandlers());

        // Add customed handler BEFORE the HttpEntityMethodProcessor to enable JsonReturnHandler !!
        final int httpEntityPos = obtainValueHandlerPosition(originalHandlers, HttpEntityMethodProcessor.class);
        HttpEntityMethodProcessor httpEntityMethodProcessor = (HttpEntityMethodProcessor) originalHandlers.get(httpEntityPos);
        originalHandlers.add(httpEntityPos - 1, new ResponseEntitySkinDTOReturnValueHandler(httpEntityMethodProcessor));
        requestMappingHandlerAdapter.setReturnValueHandlers(originalHandlers);

        //add argumentResolvers
        final List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(requestMappingHandlerAdapter.getArgumentResolvers());
        final int requestbodyPos = obtainResolverPosition(resolvers, RequestResponseBodyMethodProcessor.class);
        resolvers.add(requestbodyPos - 1, new RequestBodySkinDTOArgumentResolver());
        requestMappingHandlerAdapter.setArgumentResolvers(resolvers);


        return;
    }

    //查找指定hander在数组中的位置
    private int obtainValueHandlerPosition(final List<HandlerMethodReturnValueHandler> originalHandlers, Class<?> handlerClass) {
        for (int i = 0; i < originalHandlers.size(); i++) {
            final HandlerMethodReturnValueHandler valueHandler = originalHandlers.get(i);
            if (handlerClass.isAssignableFrom(valueHandler.getClass())) {
                return i;
            }
        }
        return -1;
    }

    //查找指定resolver在数组中的位置
    private int obtainResolverPosition(final List<HandlerMethodArgumentResolver> resolvers, Class<?> resloverClass) {
        for (int i = 0; i < resolvers.size(); i++) {
            final HandlerMethodArgumentResolver resolver = resolvers.get(i);
            if (resloverClass.isAssignableFrom(resolver.getClass())) {
                return i;
            }
        }
        return -1;
    }

这是为什么呢,这样从加载RequestMapingHandlerAdapter的时候开始分析了。

三、RequestMappingHandlerAdapter加载resolver和handler

在RequestMappingHandlerAdapter中,会执行如下方法加载resolver和Handler:

	@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
		initControllerAdviceCache();

		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) {
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

在上面的getDefaultArgumentResolvers方法中,会先加载Spring默认的,然后再加载用户自己配置的,所以用户自己配置的有可能会被拦截,而通过之前说的方式,可以让自己配置的生效。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值