SpringBoot中添加@ResponseBody注解会发生什么?

本文详细解析了SpringBoot中从接收到HTTP请求到返回响应的整个流程,包括DispatcherServlet、RequestMappingHandlerAdapter、ServletInvocableHandlerMethod等核心组件的工作原理,以及参数绑定、数据转换、异常处理等关键环节。

SpringBoot版本2.2.4.RELEASE。

【1】SpringBoot接收到请求

① springboot接收到一个请求返回json格式的列表,方法参数为JSONObject 格式,使用了注解@RequestBody

为什么这里要说明返回格式、方法参数、参数注解?因为方法参数与参数注解会影响你使用不同的参数解析器与后置处理器!通常使用WebDataBinder进行参数数据绑定结果也不同。

将要调用的目标方法如下:

    @ApiOperation(value="分页查询")
    @RequestMapping(value = "/listPage",method = RequestMethod.POST)
    @ResponseBody
    public ResponseBean listPage(@RequestBody JSONObject params){
        Integer pageNum = params.getInteger("pageNum");
        Integer pageSize = params.getInteger("pageSize");
        String vagueParam = params.getString("vagueParam");
        IPage<TbSysGoodsCategory> indexPage = new Page<>(pageNum, pageSize);
        QueryWrapper<TbSysGoodsCategory> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(vagueParam)){
            queryWrapper.like("name",vagueParam).or().like("code",vagueParam);
        }
        //排序
        queryWrapper.orderByDesc("id");
        indexPage = tbSysGoodsCategoryService.page(indexPage,queryWrapper);
        return new ResponseBean<>(true, indexPage, CommonEnum.SUCCESS_OPTION);
    }

如下所示,首先进入DispatcherServlet使用RequestMappingHandlerAdapter进行处理。
在这里插入图片描述
而RequestMappingHandlerAdapter (extends AbstractHandlerMethodAdapter)会调用父类AbstractHandlerMethodAdapter的handle方法进行处理。

AbstractHandlerMethodAdapter.handle方法源码如下:

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

	return handleInternal(request, response, (HandlerMethod) handler);
}

在这里插入图片描述
可以看到RequestMappingHandlerAdapter还实现了InitializingBean接口,该接口只有一个抽象方法afterPropertiesSet用于在BeanFactory设置完bean属性后执行,具体可参考博文:Spring - bean的初始化和销毁几种实现方式详解


② RequestMappingHandlerAdapter.handleInternal

这里首先在this.checkRequest(request)对请求进行了检测,HttpRequestMethodNotSupportedException异常就是这里抛出的。

//1.检测请求方法是否支持;
//2.检测是否需要session但是没有获取到
	protected final void checkRequest(HttpServletRequest request) throws ServletException {
		// Check whether we should support the request method.
		String method = request.getMethod();
		if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
			throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
		}

		// Check whether a session is required.
		if (this.requireSession && request.getSession(false) == null) {
			throw new HttpSessionRequiredException("Pre-existing session required but none found");
		}
	}

其他没有什么需要特殊说明的,然后直接调用了invokeHandlerMethod方法进行实际业务处理。
在这里插入图片描述


【2】RequestMappingHandlerAdapter.invokeHandlerMethod核心处理

RequestMappingHandlerAdapter.invokeHandlerMethod

这个方法十分重要,是请求处理流程中的核心方法。这个方法会根据handlerMethod获取一个ServletInvocableHandlerMethod 并对其进行各种属性设置然后调用其invokeAndHandle方法进行处理。

    @Nullable
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    // 对应 2 
        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        Object result;
        try {
// 对应 3
            WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
   // 对应 4
            ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
   // 对应 5
            ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
            if (this.argumentResolvers != null) {
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }

            if (this.returnValueHandlers != null) {
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }

            invocableMethod.setDataBinderFactory(binderFactory);
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
 // 对应 6
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//对应 7
            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
            if (asyncManager.hasConcurrentResult()) {
                result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
                    String formatted = LogFormatUtils.formatValue(result, !traceOn);
                    return "Resume with async result [" + formatted + "]";
                });
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }
//这里会跳到【3】ServletInvocableHandlerMethod.invokeAndHandle
            invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
            
            if (!asyncManager.isConcurrentHandlingStarted()) {
//这里会跳到【4】RequestMappingHandlerAdapter.getModelAndView
                ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
                return var15;
            }

            result = null;
        } finally {
        //这里会跳到【5】ServletWebRequest.requestCompleted
            webRequest.requestCompleted();
        }

        return (ModelAndView)result;
    }

① 此时的handlerMethod是什么?

如下图所示,handlermethod里面有bean、创建bean的工厂、bean的类型、原始方法method、桥接方法bridgedMethod以及参数对象parameters等关键属性。

其他都容易理解,那么什么是bridgedMethod?(后续单独分析)

在这里插入图片描述
② 此时的ServletWebRequest webRequest是什么?

这个倒是很简单,如下图所示:
在这里插入图片描述


③ 此时的WebDataBinderFactory binderFactory

WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);

RequestMappingHandlerAdapter.getDataBinderFactory源码如下:

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
//获取handlerType 
		Class<?> handlerType = handlerMethod.getBeanType();
		//根据handlerType 从initBinderCache获取到@InitBinder注解的方法
		Set<Method> methods = this.initBinderCache.get(handlerType);
		//如果initBinderCache中没有,就从handlerType查找@InitBinder注解的方法
		if (methods == null) {
			methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
			this.initBinderCache.put(handlerType, methods);
		}
		List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
		//遍历controllerAdviceBean的方法列表,从适合handlerType中拿到其方法列表
		//然后封装为一个个InvocableHandlerMethod放到initBinderMethods中
		// Global methods first
		this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
			if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
				Object bean = controllerAdviceBean.resolveBean();
				for (Method method : methodSet) {
					initBinderMethods.add(createInitBinderMethod(bean, method));
				}
			}
		});
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			initBinderMethods.add(createInitBinderMethod(bean, method));
		}
		return createDataBinderFactory(initBinderMethods);
	}

首先Class<?> handlerType = handlerMethod.getBeanType();通过handlerMethod获取到handlerTYPE,handlerTYPE声明了当前完整类路径以及类上面的注解。其值如下:
在这里插入图片描述
然后Set<Method> methods = this.initBinderCache.get(handlerType);尝试先从initBinderCache这个ConcurrentHashMap中获取当前类的使用了InitBinder注解的方法列表。如果methods为空,则从handlerType中获取使用了@InitBinder注解的方法,然后放到initBinderCache中,对应代码this.initBinderCache.put(handlerType, methods);

在这里插入图片描述

这个很关键。SpringBoot请求处理流程中最重要的一步就是数据绑定,即将参数写到目标对象上面。那么这里就涉及到参数校验、数据格式转换、绑定结果对象、错误对象等。
在这里插入图片描述

最后return createDataBinderFactory(initBinderMethods);其会拿到WebBindingInitializer创建数据绑定工厂,。

protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
			throws Exception {
		return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}

DataBinderFactory其属性ConfigurableWebBindingInitializer对象提供了基础功能,该对象中WebConversionService中转换器实例如下:
在这里插入图片描述

④ 根据handlerMethod和binderFactory获取到ModelFactory modelFactory

 ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);

RequestMappingHandlerAdapter.getModelFactory方法源码如下:

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
//获取当前handlerMethod对应的handlerType的SessionAttributesHandler 
//--如果没有就创建一个new SessionAttributesHandler(handlerType, this.sessionAttributeStore)
//参考④-①
		SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
//获取handlerType 
		Class<?> handlerType = handlerMethod.getBeanType();
//获取添加了@ModelAttribute注解的方法		
		Set<Method> methods = this.modelAttributeCache.get(handlerType);
		if (methods == null) {
			methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
			this.modelAttributeCache.put(handlerType, methods);
		}
		List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
//从controllerAdviceBean中获取适合当前handlerType的method,
//并封装为一个个InvocableHandlerMethod然后添加到attrMethods
		// Global methods first
		this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
			if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
				Object bean = controllerAdviceBean.resolveBean();
				for (Method method : methodSet) {
					attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
				}
			}
		});
//遍历methods并封装为一个个InvocableHandlerMethod然后添加到attrMethods
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			attrMethods.add(createModelAttributeM
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值