一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

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

服務(wù)器之家 - 編程語言 - Java教程 - Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter詳解

Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter詳解

2021-06-15 10:07愛寶貝丶 Java教程

這篇文章主要給大家介紹了關(guān)于Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 4399h漫画| 好奇害死猫在线观看 | 久久不射视频 | 视频在线观看入口一二三2021 | 特黄一级 | 国产精品www视频免费看 | 91在线亚洲综合在线 | 好大好深好舒服 | 国产亚洲精品一区二区在线观看 | 9热在线精品视频观看 | 丰满岳乱妇在线观看视频国产 | 久久亚洲免费视频 | 91精品国产高清久久久久 | 桃乃木香奈作品在线观看 | 久久成人国产精品一区二区 | 超强台风免费观看完整版视频 | 91天堂素人97年清纯嫩模 | 天天色视频 | 国内精品在线观看视频 | 天天翘| 好妈妈7在线观看高清 | 亚洲国产精品日本无码网站 | 天堂成人在线观看 | 国产精品视频网 | 欧美一区二区三区在线观看免费 | 春意影院午夜爽爽爽免费 | 手机在线免费观看高清 | 日产中文乱码卡一卡二 | 3d欧美人与禽交 | 青青草在线播放 | 动漫美女隐私尿口图片 | 日韩中文字幕视频在线观看 | 视频国产精品 | 99久久精品免费看国产 | 三体动漫在线观看免费完整版2022 | 韩国美女主播在线 | 亚洲精品91大神在线观看 | 免费在线观看a | 91香蕉视频在线观看 | 性xxx欧美| www.俺去|