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

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

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

服務器之家 - 編程語言 - Java教程 - spring mvc DispatcherServlet之前端控制器架構詳解

spring mvc DispatcherServlet之前端控制器架構詳解

2021-04-21 15:07一天不進步,就是退步 Java教程

這篇文章主要為大家詳細介紹了spring mvc DispatcherServlet之前端控制器架構,具有一定的參考價值,感興趣的小伙伴們可以參考一下

前端控制器是整個mvc框架中最為核心的一塊,它主要用來攔截符合要求的外部請求,并把請求分發到不同的控制器去處理,根據控制器處理后的結果,生成相應的響應發送到客戶端。前端控制器既可以使用filter實現(struts2采用這種方式),也可以使用servlet來實現(spring mvc框架)。

spring mvc DispatcherServlet之前端控制器架構詳解

dispatcherservlet 作為前置控制器是web服務器的入口,是spring mvc最重要的一個類,通過它的生命周期可以加深對web服務器的理解。

servlet的生命周期

首先我們回憶一下servlet的生命周期:

servlet生命周期分為三個階段:【servlet生命周期與工作原理詳解

  1.初始化階段  調用init()方法。servlet被裝載后,servlet容器創建一個servlet實例并且調用servlet的init()方法進行初始化。在servlet的整個生命周期內,init()方法只被調用一次。

  2.響應客戶請求階段  調用service()方法

  3.終止階段  調用destroy()方法

servlet初始化階段

  在下列時刻servlet容器裝載servlet:

  1.servlet容器啟動時自動裝載某些servlet,實現它只需要在web.xml文件中的<servlet></servlet>之間添加如下代碼:  

<loadon-startup>1</loadon-startup>
  2.在servlet容器啟動后,客戶首次向servlet發送請求

  3.servlet類文件被更新后,重新裝載servlet

dispatcherservlet的結構

復習了上述知識后我們來看看dispatcherservlet的結構:

dispatcherservlet繼承自抽象類:frameworkservlet,間接繼承了httpservlet (frameworkservlet繼承自httpservletbean,而httpservletbean繼承自httpservlet )

servlet的初始化

spring mvc DispatcherServlet之前端控制器架構詳解

?
1
2
3
4
5
6
7
8
9
10
11
protected void initstrategies(applicationcontext context) {
initmultipartresolver(context); //文件上傳解析,如果請求類型是multipart將通過multipartresolver進行文件上傳解析;
initlocaleresolver(context); //本地化解析
initthemeresolver(context);   //主題解析
inithandlermappings(context); //通過handlermapping,將請求映射到處理器
inithandleradapters(context); //通過handleradapter支持多種類型的處理器
inithandlerexceptionresolvers(context); //如果執行過程中遇到異常將交給handlerexceptionresolver來解析
initrequesttoviewnametranslator(context); //直接解析請求到視圖名
initviewresolvers(context); //通過viewresolver解析邏輯視圖名到具體視圖實現
initflashmapmanager(context); //flash映射管理器
}

servlet如何處理請求:

servlet的service方法處理http請求。

frameworkservlet.java 定義了servlet的service和destroy方法,如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* override the parent class implementation in order to intercept patch
* requests.
*/
@override
protected void service(httpservletrequest request, httpservletresponse response)
 throws servletexception, ioexception {
 
string method = request.getmethod();
if (method.equalsignorecase(requestmethod.patch.name())) {
 processrequest(request, response);
}
else {
 super.service(request, response);
}
}

我們知道http請求類型有七種(外加一個option選項),定義如下:

?
1
2
3
4
public enum requestmethod {
get, head, post, put, patch, delete, options, trace
 
}

frameworkservlet的service()處理不同的請求,我們以常見的post來說明:

?
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
/**
* process this request, publishing an event regardless of the outcome.
* <p>the actual event handling is performed by the abstract
* {@link #doservice} template method.
*/
protected final void processrequest(httpservletrequest request, httpservletresponse response)
 throws servletexception, ioexception {
 
long starttime = system.currenttimemillis();
throwable failurecause = null;
 
localecontext previouslocalecontext = localecontextholder.getlocalecontext();
localecontext localecontext = buildlocalecontext(request);
 
requestattributes previousattributes = requestcontextholder.getrequestattributes();
servletrequestattributes requestattributes = buildrequestattributes(request, response, previousattributes);
 
webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request);
asyncmanager.registercallableinterceptor(frameworkservlet.class.getname(), new requestbindinginterceptor());
 
initcontextholders(request, localecontext, requestattributes);
 
try {
 doservice(request, response);
}
catch (servletexception ex) {
 failurecause = ex;
 throw ex;
}
catch (ioexception ex) {
 failurecause = ex;
 throw ex;
}
catch (throwable ex) {
 failurecause = ex;
 throw new nestedservletexception("request processing failed", ex);
}
 
finally {
 resetcontextholders(request, previouslocalecontext, previousattributes);
 if (requestattributes != null) {
 requestattributes.requestcompleted();
 }
 
 if (logger.isdebugenabled()) {
 if (failurecause != null) {
  this.logger.debug("could not complete request", failurecause);
 }
 else {
  if (asyncmanager.isconcurrenthandlingstarted()) {
  logger.debug("leaving response open for concurrent processing");
  }
  else {
  this.logger.debug("successfully completed request");
  }
 }
 }
 
 publishrequesthandledevent(request, starttime, failurecause);
}
}

frameworkservlet 抽象定義了處理流程,留待子類來實現該方法,完成具體的請求處理。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * subclasses must implement this method to do the work of request handling,
 * receiving a centralized callback for get, post, put and delete.
 * <p>the contract is essentially the same as that for the commonly overridden
 * {@code doget} or {@code dopost} methods of httpservlet.
 * <p>this class intercepts calls to ensure that exception handling and
 * event publication takes place.
 * @param request current http request
 * @param response current http response
 * @throws exception in case of any kind of processing failure
 * @see javax.servlet.http.httpservlet#doget
 * @see javax.servlet.http.httpservlet#dopost
 */
 protected abstract void doservice(httpservletrequest request, httpservletresponse response)
  throws exception;

具體實現如下:

 

?
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
/**
* exposes the dispatcherservlet-specific request attributes and delegates to {@link #dodispatch}
* for the actual dispatching.
*/
@override
protected void doservice(httpservletrequest request, httpservletresponse response) throws exception {
if (logger.isdebugenabled()) {
 string resumed = webasyncutils.getasyncmanager(request).hasconcurrentresult() ? " resumed" : "";
 logger.debug("dispatcherservlet with name '" + getservletname() + "'" + resumed +
  " processing " + request.getmethod() + " request for [" + getrequesturi(request) + "]");
}
 
// keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
map<string, object> attributessnapshot = null;
if (webutils.isincluderequest(request)) {
 attributessnapshot = new hashmap<string, object>();
 enumeration<?> attrnames = request.getattributenames();
 while (attrnames.hasmoreelements()) {
 string attrname = (string) attrnames.nextelement();
 if (this.cleanupafterinclude || attrname.startswith("org.springframework.web.servlet")) {
  attributessnapshot.put(attrname, request.getattribute(attrname));
 }
 }
}
 
// make framework objects available to handlers and view objects.
request.setattribute(web_application_context_attribute, getwebapplicationcontext());
request.setattribute(locale_resolver_attribute, this.localeresolver);
request.setattribute(theme_resolver_attribute, this.themeresolver);
request.setattribute(theme_source_attribute, getthemesource());
 
flashmap inputflashmap = this.flashmapmanager.retrieveandupdate(request, response);
if (inputflashmap != null) {
 request.setattribute(input_flash_map_attribute, collections.unmodifiablemap(inputflashmap));
}
request.setattribute(output_flash_map_attribute, new flashmap());
request.setattribute(flash_map_manager_attribute, this.flashmapmanager);
 
try {
 dodispatch(request, response);
}
finally {
 if (webasyncutils.getasyncmanager(request).isconcurrenthandlingstarted()) {
 return;
 }
 // restore the original attribute snapshot, in case of an include.
 if (attributessnapshot != null) {
 restoreattributesafterinclude(request, attributessnapshot);
 }
}
}

重頭戲,作為請求分發器的實現:

功能:1. 把請求分發到handler(按照配置順序獲取servlet的映射關系獲取handler);2. 根據servlet已安裝的  handleradapters 去查詢第一個能處理的handler;3. handler激發處理請求

?
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
/**
* process the actual dispatching to the handler.
* <p>the handler will be obtained by applying the servlet's handlermappings in order.
* the handleradapter will be obtained by querying the servlet's installed handleradapters
* to find the first that supports the handler class.
* <p>all http methods are handled by this method. it's up to handleradapters or handlers
* themselves to decide which methods are acceptable.
* @param request current http request
* @param response current http response
* @throws exception in case of any kind of processing failure
*/
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 || mappedhandler.gethandler() == null) {
  nohandlerfound(processedrequest, response);
  return;
 }
 
 // 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 (logger.isdebugenabled()) {
  logger.debug("last-modified value for [" + getrequesturi(request) + "] is: " + lastmodified);
  }
  if (new servletwebrequest(request, response).checknotmodified(lastmodified) && isget) {
  return;
  }
 }
 
 if (!mappedhandler.applyprehandle(processedrequest, response)) {
  return;
 }
 
 try {
  // actually invoke the handler.
  mv = ha.handle(processedrequest, response, mappedhandler.gethandler());
 }
 finally {
  if (asyncmanager.isconcurrenthandlingstarted()) {
  return;
  }
 }
 
 applydefaultviewname(request, mv);
 mappedhandler.applyposthandle(processedrequest, response, mv);
 }
 catch (exception ex) {
 dispatchexception = ex;
 }
 processdispatchresult(processedrequest, response, mappedhandler, mv, dispatchexception);
}
catch (exception ex) {
 triggeraftercompletion(processedrequest, response, mappedhandler, ex);
}
catch (error err) {
 triggeraftercompletionwitherror(processedrequest, response, mappedhandler, err);
}
finally {
 if (asyncmanager.isconcurrenthandlingstarted()) {
 // instead of posthandle and aftercompletion
 mappedhandler.applyafterconcurrenthandlingstarted(processedrequest, response);
 return;
 }
 // clean up any resources used by a multipart request.
 if (multipartrequestparsed) {
 cleanupmultipart(processedrequest);
 }
}
}

servlet銷毀

?
1
2
3
4
5
6
7
8
9
10
11
12
/**
* close the webapplicationcontext of this servlet.
* @see org.springframework.context.configurableapplicationcontext#close()
*/
@override
public void destroy() {
getservletcontext().log("destroying spring frameworkservlet '" + getservletname() + "'");
// only call close() on webapplicationcontext if locally managed...
if (this.webapplicationcontext instanceof configurableapplicationcontext && !this.webapplicationcontextinjected) {
 ((configurableapplicationcontext) this.webapplicationcontext).close();
}
}

小結:

本文因篇章限制,僅僅介紹了請求處理的流程,沒有對代碼進行深入的分析,接下來的文章將從細微處著手,分析spring的代碼之美。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.cnblogs.com/davidwang456/p/4090058.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 五月天婷婷精品免费视频 | 狠狠色 | 成人免费福利网站在线看 | 东北美女野外bbwbbw免费 | 亚洲国产韩国欧美在线不卡 | 四虎伊人 | 精品国产欧美一区二区五十路 | 精品推荐国产麻豆剧传媒 | 99成人国产精品视频 | 九九精品视频在线免费观看 | 校园情射 | 亚洲欧美另类在线观看 | 成年美女黄网站色视频大全免费 | 国内精品久久久久久不卡影院 | 国产酒店自拍 | 婷婷久久精品 | 91av手机在线 | 莫莉瑞典1977k | 日本高清视频网站 | 亚洲第一男人天堂 | 污污在线免费观看 | 日韩毛片网 | 精品亚洲欧美中文字幕在线看 | www.爱情岛论坛 | 日韩免费视频一区 | japanesemoms乱熟| 色噜噜 男人的天堂在线观看 | 91精品综合 | 被黑人日 | 精品国产欧美一区二区五十路 | 国产成人精品综合在线观看 | 香蕉 在线播放 | 国产精品怡红院在线观看 | 办公室大战秘书呻吟 | 青青青国产手机在线播放 | 欧美一区a | 羞羞私人影院可以直接免费观影吗 | 欧美精品亚洲精品日韩1818 | 国产精品成人 | 国产色站| 男人亚洲天堂 |