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