国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 這一次搞懂SpringMVC原理說明

這一次搞懂SpringMVC原理說明

2020-08-27 14:13夜勿語 Java教程

這篇文章主要介紹了這一次搞懂SpringMVC原理說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

前言

前面幾篇文章,學習了Spring IOC、Bean實例化過程、AOP、事務的源碼和設計思想,了解了Spring的整體運行流程,但如果是web開發,那么必不可少的還有Spring MVC,本篇主要分析在請求調用過程中SpringMVC的實現原理,通過本篇要搞懂它是怎么解決請求、參數、返回值映射等問題的。

正文

請求入口

我們都知道前端調用后端接口時,都會通過Servlet進行轉發,而Servlet的聲明周期包含下面四個階段:

實例化(new)

初始化(init)

執行(service調用doGet/doPost)

銷毀(destroy)

前兩個階段在Spring啟動階段就做好了(init根據配置可能是第一次請求時才會調用),銷毀是服務關閉的時候進行,本文主要分析的就是請求執行階段。我們知道SpringMVC的核心就是DispatcherServlet,該類是對Servlet的擴展,所以直接從該類的service方法開始,但在此類中沒有service方法,那肯定是在其父類中,我們先來看看其繼承體系:

這一次搞懂SpringMVC原理說明

逐個往上找,在FrameworkServlet方法中就有一個service方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
 
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
 
protected void service(HttpServletRequest req, HttpServletResponse resp)
 throws ServletException, IOException
{
 String method = req.getMethod();
 
 if (method.equals(METHOD_GET)) {
  long lastModified = getLastModified(req);
  if (lastModified == -1) {
   doGet(req, resp);
  } else {
   long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
   if (ifModifiedSince < lastModified) {
    maybeSetLastModified(resp, lastModified);
    doGet(req, resp);
   } else {
    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
   }
  }
 
 } else if (method.equals(METHOD_HEAD)) {
  long lastModified = getLastModified(req);
  maybeSetLastModified(resp, lastModified);
  doHead(req, resp);
 } else if (method.equals(METHOD_POST)) {
  doPost(req, resp);
 } else if (method.equals(METHOD_PUT)) {
  doPut(req, resp);
 } else if (method.equals(METHOD_DELETE)) {
  doDelete(req, resp);
 } else if (method.equals(METHOD_OPTIONS)) {
  doOptions(req,resp);
 } else if (method.equals(METHOD_TRACE)) {
  doTrace(req,resp);
 } else {
  String errMsg = lStrings.getString("http.method_not_implemented");
  Object[] errArgs = new Object[1];
  errArgs[0] = method;
  errMsg = MessageFormat.format(errMsg, errArgs);
  
  resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
 }
}

但其主要還是調用父類HttpServlet中的方法,而該類又會根據不同的請求方式會調到子類中,最后的核心方法就是DispatcherServlet中的doDispatch方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
 HttpServletRequest processedRequest = request;
 HandlerExecutionChain mappedHandler = null;
 boolean multipartRequestParsed = false;
 
 //異步管理
 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
 try {
 ModelAndView mv = null;
 Exception dispatchException = null;
 
 try {
 //文件上傳
 processedRequest = checkMultipart(request);
 multipartRequestParsed = (processedRequest != request);
 
 //這個方法很重要,重點看
 // Determine handler for the current request.
 mappedHandler = getHandler(processedRequest);
 if (mappedHandler == null) {
  noHandlerFound(processedRequest, response);
  return;
 }
 
 //獲取跟HandlerMethod匹配的HandlerAdapter對象
 // Determine handler adapter for the current request.
 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 
 // Process last-modified header, if supported by the handler.
 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;
  }
 }
 
 //前置過濾器,如果為false則直接返回
 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  return;
 }
 
 //調用到Controller具體方法,核心方法調用,重點看看
 // Actually invoke the handler.
 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 
 if (asyncManager.isConcurrentHandlingStarted()) {
  return;
 }
 
 applyDefaultViewName(processedRequest, mv);
 
 //中置過濾器
 mappedHandler.applyPostHandle(processedRequest, response, mv);
 }
 catch (Exception ex) {
 dispatchException = ex;
 }
 catch (Throwable err) {
 // As of 4.3, we're processing Errors thrown from handler methods as well,
 // making them available for @ExceptionHandler methods and other scenarios.
 dispatchException = new NestedServletException("Handler dispatch failed", err);
 }
 
 //視圖渲染及后置過濾器執行
 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
 }
 catch (Exception ex) {
 triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
 }
 catch (Throwable err) {
 triggerAfterCompletion(processedRequest, response, mappedHandler,
  new NestedServletException("Handler processing failed", err));
 }
 finally {
 if (asyncManager.isConcurrentHandlingStarted()) {
 // Instead of postHandle and afterCompletion
 if (mappedHandler != null) {
  mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
 }
 }
 else {
 // Clean up any resources used by a multipart request.
 if (multipartRequestParsed) {
  cleanupMultipart(processedRequest);
 }
 }
 }
 }

MVC的所有處理邏輯都在這個方法中,先總結一下這個方法的實現邏輯,首先根據請求的url拿到緩存中的HandlerMethod對象和執行鏈對象,HandlerMethod中封裝了controller對象、方法對象和方法參數等信息,執行鏈則是包含了一個個HandlerInterceptor攔截器;然后再通過HandlerMethod拿到對應的HandlerAdapter,這個對象的作用就是去適配我們的controller;準備工作做完后,首先會執行前置過濾,如果被攔截則直接返回,否則就去調用controller中的方法執行我們的業務邏輯并返回一個ModelView對象;接著執行中置過濾器,以及處理全局異常捕獲器捕獲到異常;最后進行視圖渲染返回并執行后置過濾器進行資源釋放等工作。

以上就是MVC的整體執行流程,下面就逐個來分析,首先進入getHandler方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//handlerMappering實例
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
//獲取HandlerMethod和過濾器鏈的包裝類
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
 return handler;
}
}
}
return null;
}

是委托給HandlerMapping對象的,這是一個接口,主要的實現類是RequestMappingHandlerMapping,同樣先來看看其繼承體系:

這一次搞懂SpringMVC原理說明

這個類是管理請求和處理類之間的映射關系的,你是否疑惑它是在哪里實例化的呢?下面先來看看MVC組件的初始化。

組件初始化

這里我以自動化配置的注解方式說明,Spring提供了一個@EnableWebMvc,通過前面的學習我們知道在這個注解中必定導入了一個配置類,點進去可以看到是DelegatingWebMvcConfiguration,這個類就是負責MVC的組件和擴展實現的初始化,其本身我們先不看,先看其父類WebMvcConfigurationSupport,這個類我們應該不陌生,要做一些自定義擴展時就需要繼承該類(如攔截器Interceptor),同樣作用的類還有WebMvcConfigurerAdapter,這個類是對前者相對安全的擴展,為什么是相對安全呢?因為繼承前者會導致自動配置失效,而使用后者則不必擔心此問題,只需要在類上加上@EnableWebMvc注解。

在WebMvcConfigurationSupport中我們可以看到很多@Bean標注的方法,也就是mvc組件的實例化,這里主要看看requestMappingHandlerMapping,其余的可自行閱讀理解,也就是一些Bean的注冊:

?
1
2
3
4
5
6
7
8
9
10
11
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
 
......省略
 
return mapping;
}

這里主要看getInterceptors方法如何獲取攔截器的:

?
1
2
3
4
5
6
7
8
9
10
11
protected final Object[] getInterceptors() {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
//鉤子方法,需要自己定義
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}

第一次進來會調用addInterceptors添加攔截器,這是一個模板方法,在子類DelegatingWebMvcConfiguration中實現:

?
1
2
3
4
5
6
7
8
9
10
11
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
 
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
 
public void addInterceptors(InterceptorRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addInterceptors(registry);
}
}

可以看到最終是調用WebMvcConfigurer的addInterceptors方法,也就是我們對WebMvcConfigurerAdapter的自定義擴展。看到這里我們應該明白了MVC的組件是如何添加到IOC容器中的,但是DispatcherServlet又是怎么獲取到它們的呢?回到之前的代碼中,在DispatcherServlet這個類中有一個onRefresh方法,這個方法又調用了initStrategies方法完成了MVC九大組件的注冊:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
 
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
 
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
 
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
 BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
 
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
}

以initHandlerMappings為例,其它組件實現邏輯基本一樣。首先從IOC容器中拿到handlerMappings的所有實現類(WebMvcConfigurationSupport中注入的對象就在這里被獲取到),若沒有,則從DispatcherServlet.properties配置文件中(這個配置在spring-webmvc工程下org/springframework/web/servlet/DispatcherServlet.properties)獲取默認的配置:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
 
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
 
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
 
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
 
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
 org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
 org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
 
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
 
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
 
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

但是onRefresh又是在什么時候調用的呢?有兩個地方,一個是Servlet初始化時會調用到initWebApplicationContext進行容器的初始化,這個方法中就會觸發onRefresh;另外還有一個,在FrameworkServlet中有一個onApplicationEvent方法,而這個方法又會被內部類ContextRefreshListener調用,這個類實現了ApplicationListener接口,表示會接收容器刷新事件。

以上就就是MVC HandlerMapping組件的初始化邏輯,其它組件實現邏輯相同,下面不再分析。

調用Controller

回到getHandler方法,其調用的是AbstractHandlerMapping類的方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//根據請求的uri拿到對應的HandlerMethod對象
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
 
//獲取HandlerMethod和過濾器鏈的包裝類
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
 
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
 
//是否是跨域請求,就是查看request請求頭中是否有Origin屬性
if (CorsUtils.isCorsRequest(request)) {
//自定義的鉤子方法獲取跨域配置
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
//注解獲取跨域配置
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
//這里設置了跨域的過濾器CorsInterceptor
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
 
return executionChain;
}

先看AbstractHandlerMethodMapping.getHandlerInternal:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//從request對象中獲取uri,/common/query2
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
//根據uri從映射關系中找到對應的HandlerMethod對象
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//把Controller類實例化
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
 
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 根據url拿到對應的RequestMappingInfo
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
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<Match> 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);
}
}
 
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
// 拿到匹配的RequestMappingInfo對象,有可能url相同,@RequestMapping的屬性(請求方式、參數等)匹配不上
T match = getMatchingMapping(mapping, request);
if (match != null) {
//RequestMappingInfo對象和HandlerMethod對象封裝到Match對象中,其實就是注解屬性和Method對象的映射
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}

這里邏輯很簡單,就是通過請求url從urlLookup中拿到對應的RequestMappingInfo(每一個 @RequestMapping對應一個RequestMappingInfo對象)對象,再根據RequestMappingInfo對象從mappingLookup拿到對應的HandlerMethod并返回。

但這里你可能會比較好奇urlLookup和mappingLookup從哪里來的,仔細觀察你會發現當前這個類實現了一個接口InitializingBean,實現了這個接口的類會在該類的Bean實例化完成后調用afterPropertiesSet方法,上面的映射關系就是在這個方法中做的。實際上這個方法不止完成了上面兩個映射關系,還有下面兩個:

corsLookup:handlerMethod -> corsConfig

registry:RequestMappingInfo -> MappingRegistration(包含url、handlerMethod、RequestMappingInfo、name等信息)

這里就不展開分析了,奉上一張時序圖,讀者可根據下面的時序圖自行分析:

這一次搞懂SpringMVC原理說明

拿到HandlerMethod對象后,又會通過getHandlerExecutionChain方法去獲取到所有的HandlerInterceptor攔截器對象,并連同HandlerMethod對象一起封裝為HandlerExecutionChain。之后是獲取跨域配置,這里不詳細分析。

拿到HandlerExecutionChain對象后返回到doDispatch方法,又調用了getHandlerAdapter

方法拿到HandlerAdapter:

?
1
2
3
4
5
6
7
8
9
10
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//根據handlerMethod對象,找到合適的HandlerAdapter對象,這里用到了策略模式
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
 return adapter;
}
}
}
}

這里的handlerAdapters變量值從哪里來?相信不用我再分析,主要看這里的設計思想,典型的策略模式。

之后調用完前置過濾器后,才是真正調用我們controller方法的邏輯,通過HandlerAdapter.handle去調用,最終會調用到ServletInvocableHandlerMethod.invokeAndHandle:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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和handleReturnValue的調用,前者是完成參數綁定并調用controller,后者則是對返回值進行處理并封裝到ModelAndViewContainer中。先來看invokeForRequest:

?
1
2
3
4
5
6
7
8
9
10
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);
}

doInvoke就是完成反射調用,主要還是看參數綁定的實現邏輯,在getMethodArgumentValues方法中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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;
}

參數、返回值解析

因為參數類型非常多,同時還會伴隨各種注解,如:@RequestBody、@RequestParam、@PathVariable等,所以參數解析的工作是非常繁雜的,同時還要考慮到擴展性,所以SpringMVC依然采用了策略模式來完成對各種參數類型的解析綁定,其頂層接口就是HandlerMethodArgumentResolver,而默認SpringMVC提供的解析方式就高達20多種:

這一次搞懂SpringMVC原理說明

上面是類圖,讀者可根據自己熟悉的參數類型找到對應的類進行分析,最核心的還是要掌握這里的設計思想。

接著方法調用完成后就是對返回值的處理,同樣的,返回值類型也是非常多,也可以使用各種注解標注,所以也是使用策略模式實現,其頂層接口是HandlerMethodReturnValueHandler,實現類如下:

這一次搞懂SpringMVC原理說明

調用完成之后就是執行后續操作了:執行中置過濾器、處理全局異常、視圖渲染以及執行后置過濾器,這些與主流程沒有太大關系,本篇不展開分析了,最后是MVC的執行時序圖:

這一次搞懂SpringMVC原理說明

總結

本篇是Spring核心原理系列的最后一篇,前前后后花了一個月時間,終于從宏觀上大致上理解了Spring的實現原理和運行機制,明白了之前項目中一些坑是如何產生的,最主要的是學到設計模式的運用以及如何利用Spring的一些常用的擴展點進行自定義擴展。但對于Spring這個龐大的體系來說,還有很多是要去理解學習的,尤其是設計思想,只有長期琢磨才能深刻的理解掌握。在我之前的文章中包括本篇還有很多沒分析到的細節,在后面我會不定期分享出來。希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/l6108003/article/details/106770028

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 色婷婷综合久久久中文字幕 | 日韩一区在线观看视频 | 久久精品黄色 | 四虎永久免费 | 夜夜超碰 | 爱色影wwwcom | 亚洲欧美影院 | 日韩欧美国产一区二区 | 91精品国产综合久久福利软件 | 日韩欧美在线观看 | 欧美1级| 亚洲国内精品 | 午夜精品在线 | 狠狠干av| 久久国 | 日韩精品视频久久 | 国产精品一卡二卡三卡 | 中文字幕在线观看 | 日韩免费视频 | 午夜成人免费电影 | www.av在线播放 | 欧美一级二级视频 | 日韩在线亚洲 | 国产精品久久影院 | 欧美成人观看 | 亚洲欧美视频一区 | 国产毛片v一区二区三区 | 久久久中文| 日韩电影在线看 | 久久三区 | 久久久久久久久久久国产 | 狠狠操狠狠操 | 欧美久久精品一级黑人c片 成人在线视频免费观看 | 亚洲欧美综合乱码精品成人网 | 久久久久久国产一级毛片高清版 | 国产精品69毛片高清亚洲 | 中文字幕一区二区三区乱码在线 | 亚洲欧美日韩国产 | 欧美日韩精品一区二区公司 | 成人在线观看免费视频 | 成人在线免费网站 |