SpringMVC框架原理剖析(一):如何自定义一个@ResponseBody

其实在我们平常使用的@RestController注解中,就已经包含了对返回结果的处理:

其关键点便在于@ResponseBody这个注解,在我们的普通MVC框架中,在获取结果以后是要同时返回ModelAndView的,也就是数据和视图。

如果标注了@ResponseBody注解,则会触发默认的后置处理器,对返回结果进行处理,其核心方法如下:

其核心方法便是实现接口HandlerMethodReturnValueHandler中的两个方法:

public interface HandlerMethodReturnValueHandler {
    boolean supportsReturnType(MethodParameter var1);

    void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
}

通过supportsReturnType确认进入此类,然后执行handleReturnValue对返回结果进行处理。

额外说一句,DispatchServelet中的

mappedHandler.applyPostHandle(processedRequest, response, mv);

调用

HandlerInterceptor中的postHandle方法

也可以实现类似的效果,但是到了这一步中,结果已经被转换成了流对象,只能对response的字节流进行处理,这样就会麻烦许多。

接着说SpringMVC的后置处理器,我们只需要自定义一个HandlerMethodReturnValueHandler的实现类,自定义一个注解,仿照上文解析@ResponseBody注解的类的写法,便可以自定义我们自己的后置处理器,可以认为自己写了一个仿版@ResponseBody后置处理器。

在使用自定义的后置处理器的过程中,有2点需要注意,避免踩坑。

1、类上不能使用@RestController这个组合注解,要把@Controller和@ResponseBody分开,这样在普通的方法中加入@ResponseBody注解,自定义的方法加入我们自定义的注解。

2、在完成第一步以后,检查一下Controller层方法的返回类型是不是Map类型,如果是换一个。

其原因便是由于请求完成以后,后置处理器执行逻辑会遍历已经存在的后置处理器,我们自定义的一定是在@ResponseBody和Map类型的后置处理器后面,如果前面有满足条件的处理器,后面的便不会执行。

后置处理器的执行原理如下:

RequestMappingHandlerAdapter可以自定义一个controller请求的返回结果。

DispatcherServlet进入doDispatch方法,

通过mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

进入controller层,调用请求的具体方法为:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

        HttpServletRequest processedRequest = request;

        HandlerExecutionChain mappedHandler = null;

        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);



        try {

            try {

                ModelAndView mv = null;

                Object dispatchException = null;



                try {

                    processedRequest = this.checkMultipart(request);

                    multipartRequestParsed = processedRequest != request;

                    mappedHandler = this.getHandler(processedRequest);

                    if (mappedHandler == null) {

                        this.noHandlerFound(processedRequest, response);

                        return;

                    }



                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());

                    String method = request.getMethod();

                    boolean isGet = "GET".equals(method);

                    if (isGet || "HEAD".equals(method)) {

                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {

                            return;

                        }

                    }



                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {

                        return;

                    }



                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                    if (asyncManager.isConcurrentHandlingStarted()) {

                        return;

                    }

之后,再选择合适的适配器来进行controller层的调用:

@Nullable

    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        return this.handleInternal(request, response, (HandlerMethod)handler);

    }

进入找到的适配器RequestMappingHandlerAdapter执行handleInternal

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        this.checkRequest(request);

        ModelAndView mav;

        if (this.synchronizeOnSession) {

            HttpSession session = request.getSession(false);

            if (session != null) {

                Object mutex = WebUtils.getSessionMutex(session);

                synchronized(mutex) {

                    mav = this.invokeHandlerMethod(request, response, handlerMethod);

                }

            } else {

                mav = this.invokeHandlerMethod(request, response, handlerMethod);

            }

        } else {

            mav = this.invokeHandlerMethod(request, response, handlerMethod);

        }

下一步:

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

        Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);

        this.setResponseStatus(webRequest);

        if (returnValue == null) {

            if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {

                this.disableContentCachingIfNecessary(webRequest);

                mavContainer.setRequestHandled(true);

                return;

            }

        } else if (StringUtils.hasText(this.getResponseStatusReason())) {

            mavContainer.setRequestHandled(true);

            return;

        }



        mavContainer.setRequestHandled(false);

        Assert.state(this.returnValueHandlers != null, "No return value handlers");



        try {

            this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);

        } catch (Exception var6) {

            if (this.logger.isTraceEnabled()) {

                this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);

            }



            throw var6;

        }

    }

通过invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0])方法,进入controller层后(Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);),请求完成后再执行对返回数据的后置处理(this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);)。

进入HandlerMethodReturnValueHandlerComposite类中,选择合适的后置处理器,对请求成功的数据进行处理:

这时候可以对标有@ResponseBody注解的方法进行特殊的后置处理,也就是把数据转换成json,返回前端。

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);

        if (handler == null) {

            throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());

        } else {

            handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);

        }

    }

如果我们需要自定义数据的后置处理,我们可以扩展selectHandler方法中引用的returnValueHandlers属性,也就是实现上文提到的HandlerMethodReturnValueHandler接口,我们可以对其进行扩展。

@Nullable

    private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {

        boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);

        Iterator var4 = this.returnValueHandlers.iterator();



        HandlerMethodReturnValueHandler handler;

        do {

            do {

                if (!var4.hasNext()) {

                    return null;

                }



                handler = (HandlerMethodReturnValueHandler)var4.next();

            } while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));

        } while(!handler.supportsReturnType(returnType));



        return handler;

    }

依然是在HandlerMethodReturnValueHandlerComposite中,可以看到其类型为:

private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList();

那么returnValueHandlers 是如何初始化的呢?

我们可以通过在HandlerMethodReturnValueHandlerComposite中的addHandlers方法打上断点,在重启项目,就可以看到其加载来源。

通过debugger我们可以看到,在执行doGetBean的过程中,执行了afterPropertiesSet方法:

public void afterPropertiesSet() {

        this.initControllerAdviceCache();

        List handlers;

        if (this.argumentResolvers == null) {

            handlers = this.getDefaultArgumentResolvers();

            this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);

        }



        if (this.initBinderArgumentResolvers == null) {

            handlers = this.getDefaultInitBinderArgumentResolvers();

            this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);

        }



        if (this.returnValueHandlers == null) {

            handlers = this.getDefaultReturnValueHandlers();

            this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);

        }



    }

最终对

public HandlerMethodReturnValueHandlerComposite addHandlers(@Nullable List<? extends HandlerMethodReturnValueHandler> handlers) {
        if (handlers != null) {
            this.returnValueHandlers.addAll(handlers);
        }
        return this;
    }

执行了调用。

通过同一个断点,可以看到这整个流程其实就是RequestMappingHandlerAdapter这个bean的初始化过程。

也就是说在ioc容器启动的过程中对RequestMappingHandlerAdapter进行初始化的时候,通过afterPropertiesSet方法中,通过addHandlers(handlers)直接把controller执行完成后的后置处理器给配置好了。

那么关键的代码便是在RequestMappingHandlerAdapter中的:

 if (this.returnValueHandlers == null) {

            handlers = this.getDefaultReturnValueHandlers();

            this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);

        }

可以看到,第一步是先加载了默认的controller执行完成后,可能执行的handler。第二步就是把这个handlers塞给returnValueHandlers。

此后再从returnValueHandlers中选择需要执行的后置处理器。

其中关键方法便是getDefaultReturnValueHandlers:

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {

        List<HandlerMethodReturnValueHandler> handlers = new ArrayList(20);

        handlers.add(new ModelAndViewMethodReturnValueHandler());

        handlers.add(new ModelMethodProcessor());

        handlers.add(new ViewMethodReturnValueHandler());

        handlers.add(new ResponseBodyEmitterReturnValueHandler(this.getMessageConverters(), this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));

        handlers.add(new StreamingResponseBodyReturnValueHandler());

        handlers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));

        handlers.add(new HttpHeadersReturnValueHandler());

        handlers.add(new CallableMethodReturnValueHandler());

        handlers.add(new DeferredResultMethodReturnValueHandler());

        handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

        handlers.add(new ModelAttributeMethodProcessor(false));

        handlers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));

        handlers.add(new ViewNameMethodReturnValueHandler());

        handlers.add(new MapMethodProcessor());

        if (this.getCustomReturnValueHandlers() != null) {

            handlers.addAll(this.getCustomReturnValueHandlers());

        }



        if (!CollectionUtils.isEmpty(this.getModelAndViewResolvers())) {

            handlers.add(new ModelAndViewResolverMethodReturnValueHandler(this.getModelAndViewResolvers()));

        } else {

            handlers.add(new ModelAttributeMethodProcessor(true));

        }



        return handlers;

    }

可以看到,我们可以基于handlers.addAll(this.getCustomReturnValueHandlers());这段代码对后置处理器进行自定义。

可以看到RequestMappingHandlerAdapter的初始化过程就在WebMvcAutoConfiguration的内部类,EnableWebMvcConfiguration中:

   public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

        private final ResourceProperties resourceProperties;

        private final WebMvcProperties mvcProperties;

        private final WebMvcRegistrations mvcRegistrations;

        private ResourceLoader resourceLoader;

        private final ListableBeanFactory beanFactory;



        public EnableWebMvcConfiguration(ResourceProperties resourceProperties, ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {

            this.resourceProperties = resourceProperties;

            this.mvcProperties = (WebMvcProperties)mvcPropertiesProvider.getIfAvailable();

            this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();

            this.beanFactory = beanFactory;

        }



        @Bean

        public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {

            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager, conversionService, validator);

            adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());

            return adapter;

        }



    @Bean

    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {

        RequestMappingHandlerAdapter adapter = this.createRequestMappingHandlerAdapter();

        adapter.setContentNegotiationManager(contentNegotiationManager);

        adapter.setMessageConverters(this.getMessageConverters());

        adapter.setWebBindingInitializer(this.getConfigurableWebBindingInitializer(conversionService, validator));

        adapter.setCustomArgumentResolvers(this.getArgumentResolvers());

        adapter.setCustomReturnValueHandlers(this.getReturnValueHandlers());

在初始化的时候调用了setCustomReturnValueHandlers:

    public void setCustomReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {

        this.customReturnValueHandlers = returnValueHandlers;

    }

所以我们可以在

@Configuration

public class CustomWebMvcConfigurer implements WebMvcConfigurer

的配置中,自定义我们的:

   default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {

    }

以上,就是SpringMVC框架中的后置处理器实现方法和原理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值