前言
requestmappinghandleradapter實(shí)現(xiàn)了handleradapter接口,顧名思義,表示handler的adapter,這里的handler指的是spring處理具體請(qǐng)求的某個(gè)controller的方法,也就是說handleradapter指的是將當(dāng)前請(qǐng)求適配到某個(gè)handler的處理器。requestmappinghandleradapter是handleradapter的一個(gè)具體實(shí)現(xiàn),主要用于將某個(gè)請(qǐng)求適配給@requestmapping類型的handler處理。
如下是handlermapping接口的聲明:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public interface handleradapter { // 用于判斷當(dāng)前handleradapter是否能夠處理當(dāng)前請(qǐng)求 boolean supports(object handler); // 如果當(dāng)前handleradapter能夠用于適配當(dāng)前請(qǐng)求,那么就會(huì)處理當(dāng)前請(qǐng)求中 // 諸如參數(shù)和返回值等信息,以便能夠直接委托給具體的handler處理 modelandview handle(httpservletrequest request, httpservletresponse response, object handler) throws exception; // 獲取當(dāng)前請(qǐng)求的最后更改時(shí)間,主要用于供給瀏覽器判斷當(dāng)前請(qǐng)求是否修改過, // 從而判斷是否可以直接使用之前緩存的結(jié)果 long getlastmodified(httpservletrequest request, object handler); } |
1. supports()
handleradapter.supports()方法的主要作用在于判斷當(dāng)前的handleradapter是否能夠支持當(dāng)前的handler的適配。這里的handler指的是某個(gè)controller的方法,其是由handlerexecutionchain handlermapping.gethandler(httpservletrequest)方法獲取到的。從這里可以看出,handlermapping的作用主要是根據(jù)request請(qǐng)求獲取能夠處理當(dāng)前request的handler,而handleradapter的作用在于將request中的各個(gè)屬性,如request param適配為handler能夠處理的形式。
關(guān)于handleradapter.supports()方法,有這個(gè)方法的主要原因是,handlermapping是可以有多種實(shí)現(xiàn)的,spring會(huì)遍歷這些具體的實(shí)現(xiàn)類,判斷哪一個(gè)能夠根據(jù)當(dāng)前request產(chǎn)生一個(gè)handler,因而對(duì)于handleradapter而言,其是不知道當(dāng)前獲取到的handler具體是什么形式的,不同的handlermapping產(chǎn)生的handler形式是不一樣的,比如requestmappinghandlermapping產(chǎn)生的handler則是封裝在handlermethod對(duì)象中的,因而這里handleradapter需要一個(gè)方法能夠快速過濾掉當(dāng)前產(chǎn)生的handler是否為其能夠進(jìn)行適配的,這個(gè)方法就是handleradapter.supports()方法。如下是該方法的實(shí)現(xiàn):
1
2
3
4
5
6
7
8
9
|
// abstracthandlermethodadapter @override public final boolean supports(object handler) { // 判斷當(dāng)前handler是否為handlermethod類型,并且判斷supportsinternal()方法返回值是否為true, // 這里supportsinternal()方法是提供給子類實(shí)現(xiàn)的一個(gè)方法,對(duì)于requestmappinghandleradapter // 而言,其返回值始終是true,因?yàn)槠渲恍枰幚淼膆andler是handlermethod類型的即可 return (handler instanceof handlermethod && supportsinternal((handlermethod) handler)); } |
1
2
3
4
5
6
7
|
// requestmappinghandleradapter @override protected boolean supportsinternal(handlermethod handlermethod) { // 這里requestmappinghandleradapter只是對(duì)supportsinternal()返回true,因?yàn)槠渲恍枰?/code> // 處理的handler類型是handlermethod類型即可 return true ; } |
2. handle()
在supports()方法判斷了所處理的handler是handlermethod類型之后,requestmappinghandleradapter就會(huì)調(diào)用handle()方法處理當(dāng)前請(qǐng)求。該方法的主要作用在于有五點(diǎn):
- 獲取當(dāng)前spring容器中在方法上配置的標(biāo)注了@modelattribute但是沒標(biāo)注@requestmapping注解的方法,在真正調(diào)用具體的handler之前會(huì)將這些方法依次進(jìn)行調(diào)用;
- 獲取當(dāng)前spring容器中標(biāo)注了@initbinder注解的方法,調(diào)用這些方法以對(duì)一些用戶自定義的參數(shù)進(jìn)行轉(zhuǎn)換并且綁定;
- 根據(jù)當(dāng)前handler的方法參數(shù)標(biāo)注的注解類型,如@requestparam,@modelattribute等,獲取其對(duì)應(yīng)的argumentresolver,以將request中的參數(shù)轉(zhuǎn)換為當(dāng)前方法中對(duì)應(yīng)注解的類型;
- 配合轉(zhuǎn)換而來的參數(shù),通過反射調(diào)用具體的handler方法;
- 通過returnvaluehandler對(duì)返回值進(jìn)行適配,比如modelandview類型的返回值就由modelandviewmethodreturnvaluehandler處理,最終將所有的處理結(jié)果都統(tǒng)一封裝為一個(gè)modelandview類型的返回值,這也是requestmappinghandleradapter.handle()方法的返回值類型。
這里我們首先看看requestmappinghandleradapter.handle()方法的實(shí)現(xiàn)源碼:
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
|
@override protected modelandview handleinternal(httpservletrequest request, httpservletresponse response, handlermethod handlermethod) throws exception { modelandview mav; checkrequest(request); // 判斷當(dāng)前是否需要支持在同一個(gè)session中只能線性地處理請(qǐng)求 if ( this .synchronizeonsession) { // 獲取當(dāng)前請(qǐng)求的session對(duì)象 httpsession session = request.getsession( false ); if (session != null ) { // 為當(dāng)前session生成一個(gè)唯一的可以用于鎖定的key object mutex = webutils.getsessionmutex(session); synchronized (mutex) { // 對(duì)handlermethod進(jìn)行參數(shù)等的適配處理,并調(diào)用目標(biāo)handler mav = invokehandlermethod(request, response, handlermethod); } } else { // 如果當(dāng)前不存在session,則直接對(duì)handlermethod進(jìn)行適配 mav = invokehandlermethod(request, response, handlermethod); } } else { // 如果當(dāng)前不需要對(duì)session進(jìn)行同步處理,則直接對(duì)handlermethod進(jìn)行適配 mav = invokehandlermethod(request, response, handlermethod); } // 判斷當(dāng)前請(qǐng)求頭中是否包含cache-control請(qǐng)求頭,如果不包含,則對(duì)當(dāng)前response進(jìn)行處理, // 為其設(shè)置過期時(shí)間 if (!response.containsheader(header_cache_control)) { // 如果當(dāng)前sessionattribute中存在配置的attributes,則為其設(shè)置過期時(shí)間。 // 這里sessionattribute主要是通過@sessionattribute注解生成的 if (getsessionattributeshandler(handlermethod).hassessionattributes()) { applycacheseconds(response, this .cachesecondsforsessionattributehandlers); } else { // 如果當(dāng)前不存在sessionattributes,則判斷當(dāng)前是否存在cache-control設(shè)置, // 如果存在,則按照該設(shè)置進(jìn)行response處理,如果不存在,則設(shè)置response中的 // cache的過期時(shí)間為-1,即立即失效 prepareresponse(response); } } return mav; } |
上述代碼主要做了兩部分處理:①判斷當(dāng)前是否對(duì)session進(jìn)行同步處理,如果需要,則對(duì)其調(diào)用進(jìn)行加鎖,不需要?jiǎng)t直接調(diào)用;②判斷請(qǐng)求頭中是否包含cache-control請(qǐng)求頭,如果不包含,則設(shè)置其cache立即失效。可以看到,對(duì)于handlermethod的具體處理是在invokehandlermethod()方法中進(jìn)行的,如下是該方法的具體實(shí)現(xiàn):
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
|
@nullable protected modelandview invokehandlermethod(httpservletrequest request, httpservletresponse response, handlermethod handlermethod) throws exception { servletwebrequest webrequest = new servletwebrequest(request, response); try { // 獲取容器中全局配置的initbinder和當(dāng)前handlermethod所對(duì)應(yīng)的controller中 // 配置的initbinder,用于進(jìn)行參數(shù)的綁定 webdatabinderfactory binderfactory = getdatabinderfactory(handlermethod); // 獲取容器中全局配置的modelattribute和當(dāng)前當(dāng)前handlermethod所對(duì)應(yīng)的controller // 中配置的modelattribute,這些配置的方法將會(huì)在目標(biāo)方法調(diào)用之前進(jìn)行調(diào)用 modelfactory modelfactory = getmodelfactory(handlermethod, binderfactory); // 將handlermethod封裝為一個(gè)servletinvocablehandlermethod對(duì)象, // 該對(duì)象用于對(duì)當(dāng)前request的整體調(diào)用流程進(jìn)行了封裝 servletinvocablehandlermethod invocablemethod = createinvocablehandlermethod(handlermethod); if ( this .argumentresolvers != null ) { // 設(shè)置當(dāng)前容器中配置的所有argumentresolver invocablemethod.sethandlermethodargumentresolvers( this .argumentresolvers); } if ( this .returnvaluehandlers != null ) { // 設(shè)置當(dāng)前容器中配置的所有returnvaluehandler invocablemethod.sethandlermethodreturnvaluehandlers( this .returnvaluehandlers); } // 將前面創(chuàng)建的webdatabinderfactory設(shè)置到servletinvocablehandlermethod中 invocablemethod.setdatabinderfactory(binderfactory); // 設(shè)置parameternamediscoverer,該對(duì)象將按照一定的規(guī)則獲取當(dāng)前參數(shù)的名稱 invocablemethod.setparameternamediscoverer( this .parameternamediscoverer); modelandviewcontainer mavcontainer = new modelandviewcontainer(); mavcontainer.addallattributes(requestcontextutils.getinputflashmap(request)); // 這里initmodel()方法主要作用是調(diào)用前面獲取到的@modelattribute標(biāo)注的方法, // 從而達(dá)到@modelattribute標(biāo)注的方法能夠在目標(biāo)handler調(diào)用之前調(diào)用的目的 modelfactory.initmodel(webrequest, mavcontainer, invocablemethod); mavcontainer.setignoredefaultmodelonredirect( this .ignoredefaultmodelonredirect); // 獲取當(dāng)前的asyncwebrequest,這里asyncwebrequest的主要作用是用于判斷目標(biāo) // handler的返回值是否為webasynctask或defferredresult,如果是這兩種中的一種, // 則說明當(dāng)前請(qǐng)求的處理應(yīng)該是異步的。所謂的異步,指的是當(dāng)前請(qǐng)求會(huì)將controller中 // 封裝的業(yè)務(wù)邏輯放到一個(gè)線程池中進(jìn)行調(diào)用,待該調(diào)用有返回結(jié)果之后再返回到response中。 // 這種處理的優(yōu)點(diǎn)在于用于請(qǐng)求分發(fā)的線程能夠解放出來,從而處理更多的請(qǐng)求,只有待目標(biāo)任務(wù) // 完成之后才會(huì)回來將該異步任務(wù)的結(jié)果返回。 asyncwebrequest asyncwebrequest = webasyncutils .createasyncwebrequest(request, response); asyncwebrequest.settimeout( this .asyncrequesttimeout); // 封裝異步任務(wù)的線程池,request和interceptors到webasyncmanager中 webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request); asyncmanager.settaskexecutor( this .taskexecutor); asyncmanager.setasyncwebrequest(asyncwebrequest); asyncmanager.registercallableinterceptors( this .callableinterceptors); asyncmanager.registerdeferredresultinterceptors( this .deferredresultinterceptors); // 這里就是用于判斷當(dāng)前請(qǐng)求是否有異步任務(wù)結(jié)果的,如果存在,則對(duì)異步任務(wù)結(jié)果進(jìn)行封裝 if (asyncmanager.hasconcurrentresult()) { object result = asyncmanager.getconcurrentresult(); mavcontainer = (modelandviewcontainer) asyncmanager.getconcurrentresultcontext()[ 0 ]; asyncmanager.clearconcurrentresult(); if (logger.isdebugenabled()) { logger.debug( "found concurrent result value [" + result + "]" ); } // 封裝異步任務(wù)的處理結(jié)果,雖然封裝的是一個(gè)handlermethod,但只是spring簡單的封裝 // 的一個(gè)callable對(duì)象,該對(duì)象中直接將調(diào)用結(jié)果返回了。這樣封裝的目的在于能夠統(tǒng)一的 // 進(jìn)行右面的servletinvocablehandlermethod.invokeandhandle()方法的調(diào)用 invocablemethod = invocablemethod.wrapconcurrentresult(result); } // 對(duì)請(qǐng)求參數(shù)進(jìn)行處理,調(diào)用目標(biāo)handlermethod,并且將返回值封裝為一個(gè)modelandview對(duì)象 invocablemethod.invokeandhandle(webrequest, mavcontainer); if (asyncmanager.isconcurrenthandlingstarted()) { return null ; } // 對(duì)封裝的modelandview進(jìn)行處理,主要是判斷當(dāng)前請(qǐng)求是否進(jìn)行了重定向,如果進(jìn)行了重定向, // 還會(huì)判斷是否需要將flashattributes封裝到新的請(qǐng)求中 return getmodelandview(mavcontainer, modelfactory, webrequest); } finally { // 調(diào)用request destruction callbacks和對(duì)sessionattributes進(jìn)行處理 webrequest.requestcompleted(); } } |
上述代碼是requestmappinghandleradapter處理請(qǐng)求的主要流程,其主要包含四個(gè)部分:①獲取當(dāng)前容器中使用@initbinder注解注冊(cè)的屬性轉(zhuǎn)換器;②獲取當(dāng)前容器中使用@modelattribute標(biāo)注但沒有使用@requestmapping標(biāo)注的方法,并且在調(diào)用目標(biāo)方法之前調(diào)用這些方法;③判斷目標(biāo)handler返回值是否使用了webasynctask或defferredresult封裝,如果封裝了,則按照異步任務(wù)的方式進(jìn)行執(zhí)行;④處理請(qǐng)求參數(shù),調(diào)用目標(biāo)方法和處理返回值。這里我們首先看requestmappinghandleradapter是如何處理標(biāo)注@initbinder的方法的,如下是getdatabinderfactory()方法的源碼:
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
|
private webdatabinderfactory getdatabinderfactory(handlermethod handlermethod) throws exception { // 判斷當(dāng)前緩存中是否緩存了當(dāng)前bean所需要裝配的initbinder方法,如果存在,則直接從緩存中取, // 如果不存在,則在當(dāng)前bean中進(jìn)行掃描獲取 class <?> handlertype = handlermethod.getbeantype(); set<method> methods = this .initbindercache.get(handlertype); if (methods == null ) { // 在當(dāng)前bean中查找所有標(biāo)注了@initbinder注解的方法,這里init_binder_methods就是一個(gè) // 選擇器,表示只獲取使用@initbinder標(biāo)注的方法 methods = methodintrospector.selectmethods(handlertype, init_binder_methods); this .initbindercache.put(handlertype, methods); } // 這里initbinderadvicecache是在requestmappinghandleradapter初始化時(shí)同步初始化的, // 其內(nèi)包含的方法有如下兩個(gè)特點(diǎn):①當(dāng)前方法所在類使用@controlleradvice進(jìn)行標(biāo)注了; // ②當(dāng)前方法使用@initbinder進(jìn)行了標(biāo)注。也就是說其內(nèi)保存的方法可以理解為是全局類型 // 的參數(shù)綁定方法 list<invocablehandlermethod> initbindermethods = new arraylist<>(); this .initbinderadvicecache.foreach((clazz, methodset) -> { // 這里判斷的是當(dāng)前配置的全局類型的initbinder是否能夠應(yīng)用于當(dāng)前bean, // 判斷的方式主要在@controlleradvice注解中進(jìn)行了聲明,包括通過包名,類所在的包, // 接口或者注解的形式限定的范圍 if (clazz.isapplicabletobeantype(handlertype)) { object bean = clazz.resolvebean(); for (method method : methodset) { initbindermethods.add(createinitbindermethod(bean, method)); } } }); // 這里是將當(dāng)前handlermethod所在bean中的initbinder添加到需要執(zhí)行的initbindermethods中。 // 這里從添加的順序可以看出,全局類型的initbinder會(huì)在當(dāng)前bean中的initbinder之前執(zhí)行 for (method method : methods) { object bean = handlermethod.getbean(); initbindermethods.add(createinitbindermethod(bean, method)); } // 將需要執(zhí)行的initbinder封裝到initbinderdatabinderfactory中 return createdatabinderfactory(initbindermethods); } |
這里獲取initbinder的方式主要有兩種,一種是獲取全局配置的initbinder,全局類型的initbinder需要聲明的類上使用@controlleradvice進(jìn)行標(biāo)注,并且聲明方法上使用@initbinder進(jìn)行標(biāo)注;另一種則是獲取當(dāng)前handler所在類中的使用@initbinder注解標(biāo)注的方法。這兩種initbinder都會(huì)執(zhí)行,只不過全局類型的initbinder會(huì)先于局部類型的initbinder執(zhí)行。關(guān)于使用@initbinder標(biāo)注的方法的執(zhí)行時(shí)間點(diǎn),需要說明的是,因?yàn)槠渑c參數(shù)綁定有關(guān),因而其只會(huì)在參數(shù)綁定時(shí)才會(huì)執(zhí)行。
這里我們繼續(xù)看requestmappinghandleradapter是如何獲取@modelattribute標(biāo)注的方法并且執(zhí)行的,如下是getmodelfactory()方法的源碼:
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
|
private modelfactory getmodelfactory(handlermethod handlermethod, webdatabinderfactory binderfactory) { // 這里sessionattributehandler的作用是聲明幾個(gè)屬性,使其能夠在多個(gè)請(qǐng)求之間共享, // 并且其能夠保證當(dāng)前request返回的model中始終保有這些屬性 sessionattributeshandler sessionattrhandler = getsessionattributeshandler(handlermethod); // 判斷緩存中是否保存有當(dāng)前handler執(zhí)行之前所需要執(zhí)行的標(biāo)注了@modelattribute的方法 class <?> handlertype = handlermethod.getbeantype(); set<method> methods = this .modelattributecache.get(handlertype); if (methods == null ) { // 如果緩存中沒有相關(guān)屬性,那么就在當(dāng)前bean中查找所有使用@modelattribute標(biāo)注,但是 // 沒有使用@requestmapping標(biāo)注的方法,并將這些方法緩存起來 methods = methodintrospector.selectmethods(handlertype, model_attribute_methods); this .modelattributecache.put(handlertype, methods); } // 獲取全局的使用@modelattribute標(biāo)注,但是沒有使用@requestmapping標(biāo)注的方法, // 這里全局類型的方法的聲明方式需要注意的是,其所在的bean必須使用@controlleradvice進(jìn)行標(biāo)注 list<invocablehandlermethod> attrmethods = new arraylist<>(); this .modelattributeadvicecache.foreach((clazz, methodset) -> { // 判斷@controlleradvice中指定的作用的bean范圍與當(dāng)前bean是否匹配,匹配了才會(huì)對(duì)其應(yīng)用 if (clazz.isapplicabletobeantype(handlertype)) { object bean = clazz.resolvebean(); for (method method : methodset) { attrmethods.add(createmodelattributemethod(binderfactory, bean, method)); } } }); // 將當(dāng)前方法中使用@modelattribute標(biāo)注的方法添加到需要執(zhí)行的attrmethods中。從這里的添加順序 // 可以看出,全局類型的方法將會(huì)先于局部類型的方法執(zhí)行 for (method method : methods) { object bean = handlermethod.getbean(); attrmethods.add(createmodelattributemethod(binderfactory, bean, method)); } // 將需要執(zhí)行的方法等數(shù)據(jù)封裝為modelfactory對(duì)象 return new modelfactory(attrmethods, binderfactory, sessionattrhandler); } |
上述getmodelfactory()方法主要工作還是獲取當(dāng)前需要先于目標(biāo)handler執(zhí)行的方法,并且獲取的方式與前面的initbinder非常的相似,這里就不再贅述。關(guān)于這里獲取的方法,其具體的執(zhí)行過程實(shí)際上是在后面的modelfactory.initmodel()方法中進(jìn)行。這里我們直接閱讀該方法的源碼:
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
|
public void initmodel(nativewebrequest request, modelandviewcontainer container, handlermethod handlermethod) throws exception { // 在當(dāng)前request中獲取使用@sessionattribute注解聲明的參數(shù) map<string, ?> sessionattributes = this .sessionattributeshandler.retrieveattributes(request); // 將@sessionattribute聲明的參數(shù)封裝到modelandviewcontainer中 container.mergeattributes(sessionattributes); // 調(diào)用前面獲取的使用@modelattribute標(biāo)注的方法 invokemodelattributemethods(request, container); // 這里首先獲取目標(biāo)handler執(zhí)行所需的參數(shù)中與@sessionattribute同名或同類型的參數(shù), // 也就是handler想要直接從@sessionattribute中聲明的參數(shù)中獲取的參數(shù)。然后對(duì)這些參數(shù) // 進(jìn)行遍歷,首先判斷request中是否包含該屬性,如果不包含,則從之前的sessionattribute緩存 // 中獲取,如果兩個(gè)都沒有,則直接拋出異常 for (string name : findsessionattributearguments(handlermethod)) { if (!container.containsattribute(name)) { object value = this .sessionattributeshandler.retrieveattribute(request, name); if (value == null ) { throw new httpsessionrequiredexception( "expected session attribute '" + name + "'" , name); } container.addattribute(name, value); } } } |
這里initmodel()方法主要做了兩件事:①保證@sessionattribute聲明的參數(shù)的存在;②調(diào)用使用@modelattribute標(biāo)注的方法。我們直接閱讀invokemodelattributemethods()方法的源碼:
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
|
private void invokemodelattributemethods(nativewebrequest request, modelandviewcontainer container) throws exception { while (! this .modelmethods.isempty()) { // 這里getnextmodelmethod()方法始終會(huì)獲取modelmethods中的第0號(hào)為的方法, // 后續(xù)該方法執(zhí)行完了之后則會(huì)將該方法從modelmethods移除掉,因而這里while // 循環(huán)只需要判斷modelmethods是否為空即可 invocablehandlermethod modelmethod = getnextmodelmethod(container).gethandlermethod(); // 獲取當(dāng)前方法中標(biāo)注的modelattribute屬性,然后判斷當(dāng)前request中是否有與該屬性中name字段 // 標(biāo)注的值相同的屬性,如果存在,并且當(dāng)前modelattribute設(shè)置了不對(duì)該屬性進(jìn)行綁定,那么 // 就直接略過當(dāng)前方法的執(zhí)行 modelattribute ann = modelmethod.getmethodannotation(modelattribute. class ); assert .state(ann != null , "no modelattribute annotation" ); if (container.containsattribute(ann.name())) { if (!ann.binding()) { container.setbindingdisabled(ann.name()); } continue ; } // 通過argumentresolver對(duì)方法參數(shù)進(jìn)行處理,并且調(diào)用目標(biāo)方法 object returnvalue = modelmethod.invokeforrequest(request, container); // 如果當(dāng)前方法的返回值不為空,則判斷當(dāng)前@modelattribute是否設(shè)置了需要綁定返回值, // 如果設(shè)置了,則將返回值綁定到請(qǐng)求中,后續(xù)handler可以直接使用該參數(shù) if (!modelmethod.isvoid()){ string returnvaluename = getnameforreturnvalue(returnvalue, modelmethod.getreturntype()); if (!ann.binding()) { container.setbindingdisabled(returnvaluename); } // 如果request中不包含該參數(shù),則將該返回值添加到modelandviewcontainer中, // 供handler使用 if (!container.containsattribute(returnvaluename)) { container.addattribute(returnvaluename, returnvalue); } } } } |
這里調(diào)用使用@modelattribute標(biāo)注的方法的方式比較簡單,主要需要注意的是,對(duì)于調(diào)用結(jié)果,如果當(dāng)前request中沒有同名的參數(shù),則會(huì)將調(diào)用結(jié)果添加到modelandviewcontainer中,以供給后續(xù)handler使用。
在調(diào)用完使用上述方法之后,spring會(huì)判斷當(dāng)前handler的返回值是否為webasynctask或defferredresult類型,如果是這兩種類型的一種,那么就會(huì)將這些任務(wù)放入一個(gè)線程池中進(jìn)行異步調(diào)用,而當(dāng)前線程則可以繼續(xù)進(jìn)行請(qǐng)求的分發(fā)。這里這種設(shè)計(jì)的目的是,默認(rèn)情況下spring處理請(qǐng)求都是同步的,也就是說進(jìn)行請(qǐng)求分發(fā)的線程是會(huì)調(diào)用用戶所聲明的handler方法的,那么如果用戶聲明的handler執(zhí)行時(shí)間較長,就可能導(dǎo)致spring用于請(qǐng)求處理的線程都耗在了處理這些業(yè)務(wù)代碼上,也就導(dǎo)致后續(xù)的請(qǐng)求必須等待,這在高并發(fā)的場景中是不能被允許的,因而這里spring提供了一種異步任務(wù)處理的方式,也就是進(jìn)行請(qǐng)求分發(fā)的線程只需要將用戶的業(yè)務(wù)任務(wù)放到線程池中執(zhí)行即可,其自身可以繼續(xù)進(jìn)行其他的請(qǐng)求的分發(fā)。如果線程池中的任務(wù)處理完成,其會(huì)通知spring將處理結(jié)果返回給調(diào)用方。關(guān)于異步任務(wù)的處理流程,我們后面會(huì)使用專門的章節(jié)進(jìn)行講解,這里只是簡單的講解其主要功能。
在進(jìn)行了相關(guān)前置方法調(diào)用和異步任務(wù)的判斷之后,requestmappinghandleradapter就會(huì)開始調(diào)用目標(biāo)handler了。調(diào)用過程在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
33
34
35
36
|
public void invokeandhandle(servletwebrequest webrequest, modelandviewcontainer mavcontainer, object... providedargs) throws exception { // 對(duì)目標(biāo)handler的參數(shù)進(jìn)行處理,并且調(diào)用目標(biāo)handler object returnvalue = invokeforrequest(webrequest, mavcontainer, providedargs); // 設(shè)置相關(guān)的返回狀態(tài) setresponsestatus(webrequest); // 如果請(qǐng)求處理完成,則設(shè)置requesthandled屬性 if (returnvalue == null ) { if (isrequestnotmodified(webrequest) || getresponsestatus() != null || mavcontainer.isrequesthandled()) { mavcontainer.setrequesthandled( true ); return ; } } else if (stringutils.hastext(getresponsestatusreason())) { // 如果請(qǐng)求失敗,但是有錯(cuò)誤原因,那么也會(huì)設(shè)置requesthandled屬性 mavcontainer.setrequesthandled( true ); return ; } mavcontainer.setrequesthandled( false ); assert .state( this .returnvaluehandlers != null , "no return value handlers" ); try { // 遍歷當(dāng)前容器中所有returnvaluehandler,判斷哪種handler支持當(dāng)前返回值的處理, // 如果支持,則使用該handler處理該返回值 this .returnvaluehandlers.handlereturnvalue( returnvalue, getreturnvaluetype(returnvalue), mavcontainer, webrequest); } catch (exception ex) { if (logger.istraceenabled()) { logger.trace(getreturnvaluehandlingerrormessage( "error handling return value" , returnvalue), ex); } throw ex; } } |
對(duì)于handler的調(diào)用過程,這里主要分為三個(gè)步驟:①處理請(qǐng)求參數(shù)進(jìn)行處理,將request中的參數(shù)封裝為當(dāng)前handler的參數(shù)的形式;②通過反射調(diào)用當(dāng)前handler;③對(duì)方法的返回值進(jìn)行處理,以將其封裝為一個(gè)modleandview對(duì)象。這里第一步和第二步封裝在了invokeforrequest()方法中,我們首先看該方法的源碼:
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
|
@nullable public object invokeforrequest(nativewebrequest request, @nullable modelandviewcontainer mavcontainer, object... providedargs) throws exception { // 將request中的參數(shù)轉(zhuǎn)換為當(dāng)前handler的參數(shù)形式 object[] args = getmethodargumentvalues(request, mavcontainer, providedargs); if (logger.istraceenabled()) { logger.trace( "invoking '" + classutils.getqualifiedmethodname(getmethod(), getbeantype()) + "' with arguments " + arrays.tostring(args)); } // 這里doinvoke()方法主要是結(jié)合處理后的參數(shù),使用反射對(duì)目標(biāo)方法進(jìn)行調(diào)用 object returnvalue = doinvoke(args); if (logger.istraceenabled()) { logger.trace( "method [" + classutils.getqualifiedmethodname(getmethod(), getbeantype()) + "] returned [" + returnvalue + "]" ); } return returnvalue; } // 本方法主要是通過當(dāng)前容器中配置的argumentresolver對(duì)request中的參數(shù)進(jìn)行轉(zhuǎn)化, // 將其處理為目標(biāo)handler的參數(shù)的形式 private object[] getmethodargumentvalues(nativewebrequest request, @nullable modelandviewcontainer mavcontainer, object... providedargs) throws exception { // 獲取當(dāng)前handler所聲明的所有參數(shù),主要包括參數(shù)名,參數(shù)類型,參數(shù)位置,所標(biāo)注的注解等等屬性 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); // providedargs是調(diào)用方提供的參數(shù),這里主要是判斷這些參數(shù)中是否有當(dāng)前類型 // 或其子類型的參數(shù),如果有,則直接使用調(diào)用方提供的參數(shù),對(duì)于請(qǐng)求處理而言,默認(rèn)情況下, // 調(diào)用方提供的參數(shù)都是長度為0的數(shù)組 args[i] = resolveprovidedargument(parameter, providedargs); if (args[i] != null ) { continue ; } // 如果在調(diào)用方提供的參數(shù)中不能找到當(dāng)前類型的參數(shù)值,則遍歷spring容器中所有的 // argumentresolver,判斷哪種類型的resolver支持對(duì)當(dāng)前參數(shù)的解析,這里的判斷 // 方式比較簡單,比如requestparammethodargumentresolver就是判斷當(dāng)前參數(shù) // 是否使用@requestparam注解進(jìn)行了標(biāo)注 if ( this .argumentresolvers.supportsparameter(parameter)) { try { // 如果能夠找到對(duì)當(dāng)前參數(shù)進(jìn)行處理的argumentresolver,則調(diào)用其 // resolveargument()方法從request中獲取對(duì)應(yīng)的參數(shù)值,并且進(jìn)行轉(zhuǎn)換 args[i] = this .argumentresolvers.resolveargument( parameter, mavcontainer, request, this .databinderfactory); continue ; } catch (exception ex) { if (logger.isdebugenabled()) { logger.debug(getargumentresolutionerrormessage( "failed to resolve" , i), ex); } throw ex; } } // 如果進(jìn)行了參數(shù)處理之后當(dāng)前參數(shù)還是為空,則拋出異常 if (args[i] == null ) { throw new illegalstateexception( "could not resolve method parameter at index " + parameter.getparameterindex() + " in " + parameter.getexecutable().togenericstring() + ": " + getargumentresolutionerrormessage( "no suitable resolver for" ,i)); } } return args; } |
關(guān)于handler的調(diào)用,可以看到,這里的實(shí)現(xiàn)也是比較簡單的,首先是遍歷所有的參數(shù),并且查找哪種argumentresolver能夠處理當(dāng)前參數(shù),找到了則按照具體的resolver定義的方式進(jìn)行處理即可。在所有的參數(shù)處理完成之后,requestmappinghandleradapter就會(huì)使用反射調(diào)用目標(biāo)handler。
對(duì)于返回值的處理,其形式與對(duì)參數(shù)的處理非常相似,都是對(duì)returnvaluehandler進(jìn)行遍歷,判斷哪種handler能夠支持當(dāng)前返回值的處理,如果找到了,則按照其規(guī)則進(jìn)行處理即可。如下是該過程的主要流程代碼:
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
|
@override public void handlereturnvalue( @nullable object returnvalue, methodparameter returntype, modelandviewcontainer mavcontainer, nativewebrequest webrequest) throws exception { // 獲取能夠處理當(dāng)前返回值的handler,比如如果返回值是modelandview類型,那么這里的handler就是 // modelandviewmethodreturnvaluehandler handlermethodreturnvaluehandler handler = selecthandler(returnvalue, returntype); if (handler == null ) { throw new illegalargumentexception( "unknown return value type: " + returntype.getparametertype().getname()); } // 通過獲取到的handler處理返回值,并將其封裝到modelandviewcontainer中 handler.handlereturnvalue(returnvalue, returntype, mavcontainer, webrequest); } // 本方法的主要作用是獲取能夠處理當(dāng)前返回值的returnvaluehandler private handlermethodreturnvaluehandler selecthandler( @nullable object value, methodparameter returntype) { // 判斷返回值是否為異步類型的返回值,即webasynctask或defferredresult boolean isasyncvalue = isasyncreturnvalue(value, returntype); // 對(duì)所有的returnvaluehandler進(jìn)行遍歷,判斷其是否支持當(dāng)前返回值的處理。這里如果當(dāng)前返回值 // 是異步類型的返回值,還會(huì)判斷當(dāng)前returnvaluehandler是否為 // asynchandlermethodreturnvaluehandler類型,如果不是,則會(huì)繼續(xù)查找 for (handlermethodreturnvaluehandler handler : this .returnvaluehandlers) { if (isasyncvalue && !(handler instanceof asynchandlermethodreturnvaluehandler)) { continue ; } // 判斷是否支持返回值處理的主要位置,比如modelandviewmethodreturnvaluehandler就會(huì) // 判斷返回值是否為modelandview類型,如果是,則表示其是當(dāng)前returnvalulehandler所支持的類型 if (handler.supportsreturntype(returntype)) { return handler; } } return null ; } |
3. 小結(jié)
本文首先講解了requestmappinghandlermapping所做的工作與requestmappinghandleradapter的區(qū)別,然后講解requestmappinghandleradapter是如何判斷當(dāng)前的handler是否為其所支持的類型的,最后詳細(xì)講解了其是如果將request適配為目標(biāo)handler能夠調(diào)用的形式的。總的來講,requestmappinghandleradapter的主要作用就是調(diào)用requestmappinghandlermapping所獲取到的handler,然后將返回值封裝為一個(gè)modelandview對(duì)象,該對(duì)象中保存了所要渲染的視圖名稱和渲染視圖時(shí)所需要的參數(shù)值,而具體的渲染過程則是通過view對(duì)象進(jìn)行的。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。
原文鏈接:https://my.oschina.net/zhangxufeng/blog/2222270