[16]springmvc请求响应核心调用流程和过滤器

CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}

return executionChain;
}

进入getHandlerInternal方法

所在类:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 从request对象中获取 URL,/common/query2
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
// 根据 URL 从映射关系中找到对应的 HandlerMethod 对象
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 执行beanFactory.getBean的过程,获取Controller实例
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}

::: warning 知识点
lookupHandlerMethod方法之所以可以从映射关系中拿到HandlerMethod对象,是因为AbstractHandlerMethodMapping类实现了InitializingBean接口,在afterPropertiesSet方法里建立好了映射关系。
:::

进入lookupHandlerMethod方法

所在类:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List matches = new ArrayList<>();
List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 匹配过程,是否符合 RequestMappingInfo 里的属性值
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings…
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}

if (!matches.isEmpty()) {
Comparator comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
// 如果两个 RequestMappinginfo 什么都相同,报错
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
“Ambiguous handler methods mapped for '” + uri + “': {” + m1 + ", " + m2 + “}”);
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}

::: warning 知识点
addMatchingMappings方法,主要一个匹配过程,匹配@RequestMapping注解中的属性值是否满足

/*

  • consumes:指定处理请求的提交内容类型(Content-Type),
  • 例如application/json, text/html;
  • produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
  • params: 指定request中必须包含某些参数值是,才让该方法处理。
  • headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
  • */
    @RequestMapping(value = “/getUser”,
    method = RequestMethod.GET,
    params = “username=jack”,
    consumes = “application/json”,
    produces = “application/json”,
    headers = “Referer=http://www.xx.com/”)

:::

返回getHandler,进入getHandlerExecutionChain方法

所在类:org.springframework.web.servlet.handler.AbstractHandlerMapping

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 如果没有获得则创建一个 HandlerExecutionChain
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 获取当前的请求地址: /user/xxx
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 在 HandlerExecutionChain 中添加拦截器
// 遍历 SpringMVC 容器的所有拦截器
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 判断拦截器类型,如果是 MappedInterceptor 类型
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// 则先匹配路径后再添加到执行链
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
// 否则直接添加到执行链
chain.addInterceptor(interceptor);
}
}
return chain;
}

::: warning 知识点
getHandlerExecutionChain中的HandlerInterceptor拦截器是Spring MVC中的,Spring AOP中的拦截器是MethodInterceptor
:::

拿到当前请求对应的handler后,

返回主流程,进入getHandlerAdapter方法

所在类:org.springframework.web.servlet.DispatcherServlet

/**

  • TODO : 根据 handlerMethod对象,找到合适的 HandlerAdapter对象,这里用到了策略模式
    */
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
    for (HandlerAdapter adapter : this.handlerAdapters) {
    if (adapter.supports(handler)) {
    // 返回一个可以支持的HandlerAdapter 处理程序实例
    return adapter;
    }
    }
    }
    throw new ServletException(“No adapter for handler [” + handler +
    “]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler”);
    }

::: warning 知识点

HandlerAdapter 是什么
HandlerAdapter是一个接口,充当自身与处理程序对象之间的桥梁,从而导致松散耦合设计。HandlerAdapter主要处理方法参数、相关注解、数据绑定、消息转换、返回值、调用视图解析器等。

  • RequestMappingHandlerMapping为当前的请求找到合适的处理程序方法。
  • RequestMappingHandlerAdapter执行这个处理程序方法,并为它提供反射调用所需要的参数。

HandlerAdapter UML 图

HandlerAdapter的4个实现类:

  1. SimpleServletHandlerAdapter: 适配实现 Servlet 接口的 Handler, 默认调用其service方法
  1. SimpleControllerHandlerAdapter: 适配实现 Controller 接口的 Handler, 默认调用其 handleRequest 方法
  2. HttpRequestHandlerAdapter: 适配实现 HttpRequestHandler 接口的 Handler, 默认调用其 handleRequest 方法
  3. RequestMappingHandlerAdapter: 适配被@RequestMapping注释的方式, 一般都是解析一个一个参数, 并且通过反射进行激活

HandlerAdapter 总结
HandlerAdapter Spring MVC中扩展机制的非常好的一个体现,,通过 HandlerAdapter这种设计模式, DispatcherServlet 就可以支持任何格式的Handler(这里的可以支持指在不改变 DispatcherServlet 的情况下),第二是HandlerAdapter 基于不同Handler实现不同实现类(策略模式),最后也是最重要的就是参数的解析与返回值的解析。

:::

::: danger 为什么要用HandlerAdapter适配器模式?
首先, Controller的定义有多种 ,一种是带@Controller注解的, 还可以写一个servlet 当做controller, 所以用适配器做适配,不同子类实现HandlerAdapter接口,定义自己的业务逻辑,每个子类都是适配某一种类型的控制器,有了HandlerAdapter,你只需要调用自己实现的handle方法,屏蔽了不一致的细节,对用户来说直接找到对应的处理方法,无须关系哪个实现方法,否则只能在DispatcherServlet里面通过if else来处理了。
:::

前置过滤器

返回主流程,进入applyPreHandle方法,前置过滤器

所在类:org.springframework.web.servlet.DispatcherServlet

/**

  • TODO : 调用所有的 HandlerInterceptor 拦截器并调用其 preHandler方法
    */
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 获取所有的拦截器
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
    for (int i = 0; i < interceptors.length; i++) {
    HandlerInterceptor interceptor = interceptors[i];
    // 分别调用拦截器的 preHandle 方法
    if (!interceptor.preHandle(request, response, this.handler)) {
    triggerAfterCompletion(request, response, null);
    return false;
    }
    // 如果失败,记录最后一次拦截器的位置,倒序释放
    this.interceptorIndex = i;
    }
    }
    return true;
    }

返回主流程,进入handle方法,调用具体Controller的方法

最终会进入AbstractHandlerMethodAdapterhandle方法,

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}

进入handleInternal方法,

所在类:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

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

ModelAndView mav;
checkRequest(request);

// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
// 执行 HandlerMethod,返回 ModelAndView
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all…
// 执行 HandlerMethod,返回 ModelAndView
mav = invokeHandlerMethod(request, response, handlerMethod);
}

if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}

return mav;
}

进入invokeHandlerMethod方法,

所在类:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

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

ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 获取数据绑定工厂 @InitBinder注解支持,
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// Model工厂,收集了@ModelAttribute注解的方法
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//可调用的方法对象
ServletInvocableHandlerMethod invocableMethod = 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);

ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 调用有 @ModelAttribute注解的方法。每次请求都会调用有 @ModelAttribute注解的方法
//把 @ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的 map中了
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

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()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return “Resume with async result [” + formatted + “]”;
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// Controller方法调用,重点看看
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}

::: warning 知识点
invokeHandlerMethod方法主要进行了数据和参数的绑定、创建ModelAndViewContainer 视图容器,以及相关初始化工作。
:::

进入invokeAndHandle方法

所在类:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object… providedArgs) throws Exception {
// 具体调用逻辑,重点看
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);

if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}

mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, “No return value handlers”);
try {
// 返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}

进入invokeForRequest方法

所在类:org.springframework.web.method.support.InvocableHandlerMethod

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object… providedArgs) throws Exception {
// 获取参数数组,重点看
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}

进入getMethodArgumentValues方法

所在类:org.springframework.web.method.support.InvocableHandlerMethod

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object… providedArgs) throws Exception {

if (ObjectUtils.isEmpty(getMethodParameters())) {
return EMPTY_ARGS;
}
// 入参的包装类,里面包装了参数类型,参数名称,参数注解等等信息
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
// 设置参数名称解析器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 典型的策略模式,根据 parameter 能否找到对应参数的处理类,能找到就返回true
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, “No suitable resolver”));
}
try {
// 具体参数值解析过程,重点看看
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled…
if (logger.isDebugEnabled()) {
String error = ex.getMessage();
if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, error));
}
}
throw ex;
}
}
return args;
}

进入resolveArgument方法

所在类:org.springframework.web.method.support.HandlerMethodArgumentResolverComposite

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

年进入阿里一直到现在。**

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-YKsULBxO-1710846695629)]
[外链图片转存中…(img-GhFjbrms-1710846695630)]
[外链图片转存中…(img-7jco4IM1-1710846695630)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-761rpvTS-1710846695630)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值