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

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

最低0.47元/天 解锁文章
1066

被折叠的 条评论
为什么被折叠?



