📄 java开源笔记:spring源代码解析.htm
字号:
Spring
Controller的映射,比如SimpleUrl<BR>HandlerMaaping中就定义了一个map来持有这一系列的映射关系。<BR>DisptcherServlet通过HandlerMapping使得Web应用程序确定一个执行路径,就像我们在HanderMapping中看到的那样,HandlerMapping只是一个借口:<BR>public
interface HandlerMapping {<BR>public static final String
PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE
=<BR>Conventions.getQualifiedAttributeName(HandlerMapping.class,
"pathWithinHandlerMapping");<BR>//实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器<BR>HandlerExecutionChain
getHandler(HttpServletRequest request) throws
Exception;<BR>}<BR>他的具体实现只需要实现一个接口方法,而这个接口方法返回的是一个HandlerExecutionChain,实际上就是一个执行链,就像在Command模式描述的那样,这个类很简单,就是一个持有一个Interceptor链和一个Controller:<BR>public
class HandlerExecutionChain {<BR><BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">private Object handler;</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">private HandlerInterceptor[]
interceptors;</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><BR>........<BR>}<BR>而这些Handler和Interceptor需要我们定义HandlerMapping的时候配置好,比如对具体的SimpleURLHandlerMapping,他要做的就是根据URL映射的方式注册Handler和Interceptor,自己维护一个放映映射的handlerMap,当需要匹配Http请求的时候需要使用这个表里的信息来得到执行链。这个注册的过程在IOC容器初始化SimpleUrlHandlerMapping的时候就被完成了,这样以后的解析才可以用到map里的映射信息,这里的信息和bean文件的信息是等价的,下面是具体的注册过程:<BR>protected
void registerHandlers(Map urlMap) throws BeansException {<BR>if
(urlMap.isEmpty()) {<BR>logger.warn("Neither 'urlMap' nor 'mappings' set on
SimpleUrlHandlerMapping");<BR>}<BR>else
{<BR>//这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素<BR>Iterator it =
urlMap.keySet().iterator();<BR>while (it.hasNext()) {<BR>//这里取得配置的url<BR>String
url = (String) it.next();<BR>//这里根据url在bean定义中取得对应的handler<BR>Object handler =
urlMap.get(url);<BR>// Prepend with slash if not already present.<BR>if
(!url.startsWith("/")) {<BR>url = "/" +
url;<BR>}<BR>//这里调用AbstractHandlerMapping中的注册过程<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">registerHandler(url,
handler);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>}<BR>}<BR>在AbstractMappingHandler中的注册代码:<BR>protected
void registerHandler(String urlPath, Object handler) throws BeansException,
IllegalStateException {<BR>//试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系<BR>Object
mappedHandler = this.handlerMap.get(urlPath);<BR>if (mappedHandler != null)
{<BR>........<BR>}<BR><BR>//如果是直接用bean名做映射那就直接从容器中取handler<BR>if
(!this.lazyInitHandlers && handler instanceof String) {<BR>String
handlerName = (String) handler;<BR>if
(getApplicationContext().isSingleton(handlerName)) {<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">handler =
getApplicationContext().getBean(handlerName);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>}<BR>//或者使用默认的handler.<BR>if
(urlPath.equals("/*")) {<BR>setDefaultHandler(handler);<BR>}<BR>else
{<BR>//把url和handler的对应关系放到handlerMap中去<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">this.handlerMap.put(urlPath,
handler);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">........<BR>}<BR>}<BR>handlerMap是持有的一个HashMap,里面就保存了具体的映射信息:<BR>private
final Map handlerMap = new
HashMap();<BR>而SimpleUrlHandlerMapping对接口HandlerMapping的实现是这样的,这个getHandler根据在初始化的时候就得到的映射表来生成DispatcherServlet需要的执行链<BR>public
final HandlerExecutionChain getHandler(HttpServletRequest request) throws
Exception
{<BR>//这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">Object handler =
getHandlerInternal(request);<BR>//如果找不到对应的,就使用缺省的handler<BR
style="BACKGROUND-COLOR: rgb(255,255,102)"></SPAN>if (handler == null)
{<BR>handler = this.defaultHandler;<BR>}<BR>//如果缺省的也没有,那就没办法了<BR>if (handler ==
null) {<BR>return null;<BR>}<BR>// 如果handler不是一个具体的handler,那我们还要到上下文中取<BR>if
(handler instanceof String) {<BR>String handlerName = (String)
handler;<BR>handler =
getApplicationContext().getBean(handlerName);<BR>}<BR>//生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。<BR>return
new HandlerExecutionChain(handler,
this.adaptedInterceptors);<BR>}<BR>我们看看具体的handler查找过程:<BR>protected Object
getHandlerInternal(HttpServletRequest request) throws Exception {<BR>//这里的HTTP
Request传进来的参数进行分析,得到具体的路径信息。<BR>String lookupPath =
this.urlPathHelper.getLookupPathForRequest(request);<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">.......//下面是根据请求信息的查找<BR>return
lookupHandler(lookupPath, request);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR><BR>protected Object
lookupHandler(String urlPath, HttpServletRequest request) {<BR>//
如果能够直接能在SimpleUrlHandlerMapping的映射表中找到,那最好。<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">Object handler =
this.handlerMap.get(urlPath);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">if (handler == null) {<BR>//
这里使用模式来对map中的所有handler进行匹配,调用了Jre中的Matcher类来完成匹配处理。<BR>String bestPathMatch =
null;<BR>for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();)
{<BR>String registeredPath = (String) it.next();<BR>if
(this.pathMatcher.match(registeredPath, urlPath) &&<BR>(bestPathMatch ==
null || bestPathMatch.length() <= registeredPath.length())) {<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">//这里根据匹配路径找到最象的一个<BR>handler =
this.handlerMap.get(registeredPath);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">bestPathMatch =
registeredPath;<BR>}<BR>}<BR><BR>if (handler != null)
{<BR>exposePathWithinMapping(this.pathMatcher.extractPathWithinPattern(bestPathMatch,
urlPath), request);<BR>}<BR>}<BR>else {<BR>exposePathWithinMapping(urlPath,
request);<BR>}<BR>//<BR>return handler;<BR>}<BR>我
们可以看到,总是在handlerMap这个HashMap中找,当然如果直接找到最好,如果找不到,就看看是不是能通过Match
Pattern的模式找,我们一定还记得在配置HnaderMapping的时候是可以通过ANT语法进行配置的,其中的处理就在这里。<BR>这样可以清楚地看到整个HandlerMapping的初始化过程
- 同时,我们也看到了一个具体的handler映射是怎样被存储和查找的 -
这里生成一个ExecutionChain来储存我们找到的handler和在定义bean的时候定义的Interceptors.<BR>让我们回到DispatcherServlet,初始化完成以后,实际的对web请求是在doService()方法中处理的,我们知道DispatcherServlet只是一个普通的Servlet:<BR>protected
void doService(HttpServletRequest request, HttpServletResponse response) throws
Exception {<BR>.......<BR>//这里把属性信息进行保存<BR>Map attributesSnapshot = null;<BR>if
(WebUtils.isIncludeRequest(request)) {<BR>logger.debug("Taking snapshot of
request attributes before include");<BR>attributesSnapshot = new
HashMap();<BR>Enumeration attrNames = request.getAttributeNames();<BR>while
(attrNames.hasMoreElements()) {<BR>String attrName = (String)
attrNames.nextElement();<BR>if (this.cleanupAfterInclude ||
attrName.startsWith(DispatcherServlet.class.getName()))
{<BR>attributesSnapshot.put(attrName,
request.getAttribute(attrName));<BR>}<BR>}<BR>}<BR><BR>// Make framework objects
available to handlers and view
objects.<BR>request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,
getWebApplicationContext());<BR>request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE,
this.localeResolver);<BR>request.setAttribute(THEME_RESOLVER_ATTRIBUTE,
this.themeResolver);<BR>request.setAttribute(THEME_SOURCE_ATTRIBUTE,
getThemeSource());<BR><BR>try {<BR>//这里使实际的处理入口<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">doDispatch(request,
response);</SPAN><BR style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>finally
{<BR>// Restore the original attribute snapshot, in case of an include.<BR>if
(attributesSnapshot != null) {<BR>restoreAttributesAfterInclude(request,
attributesSnapshot);<BR>}<BR>}<BR>}<BR>我们看到,对于请求的处理实际上是让doDispatch()来完成的 -
这个方法很长,但是过程很简单明了:<BR>protected void doDispatch(final HttpServletRequest request,
HttpServletResponse response) throws Exception {<BR>HttpServletRequest
processedRequest =
request;<BR>//这是从handlerMapping中得到的执行链<BR>HandlerExecutionChain mappedHandler =
null;<BR>int interceptorIndex = -1;<BR><BR>........<BR>try
{<BR>//我们熟悉的ModelAndView开始出现了。<BR>ModelAndView mv = null;<BR>try
{<BR>processedRequest = checkMultipart(request);<BR><BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">// 这是我们得到handler的过程</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">mappedHandler =
getHandler(processedRequest, false);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">if (mappedHandler == null ||
mappedHandler.getHandler() == null) {<BR>noHandlerFound(processedRequest,
response);<BR>return;<BR>}<BR><BR>// 这里取出执行链中的Interceptor进行前处理<BR>if
(mappedHandler.getInterceptors() != null) {<BR>for (int i = 0; i <
mappedHandler.getInterceptors().length; i++) {<BR>HandlerInterceptor interceptor
= mappedHandler.getInterceptors()[i];<BR>if
(!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler()))
{<BR>triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest,
response, null);<BR>return;<BR>}<BR>interceptorIndex =
i;<BR>}<BR>}<BR><BR>//在执行handler之前,用HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的。<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">HandlerAdapter ha =
getHandlerAdapter(mappedHandler.getHandler());</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">mv = ha.handle(processedRequest,
response, mappedHandler.getHandler());</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><BR>//
这里取出执行链中的Interceptor进行后处理<BR>if (mappedHandler.getInterceptors() != null)
{<BR>for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i--)
{<BR>HandlerInterceptor interceptor =
mappedHandler.getInterceptors()[i];<BR>interceptor.postHandle(processedRequest,
response, mappedHandler.getHandler(),
mv);<BR>}<BR>}<BR>}<BR><BR>........<BR><BR>// Did the handler return a view to
render?<BR>//这里对视图生成进行处理<BR><SPAN style="BACKGROUND-COLOR: rgb(255,255,102)">if
(mv != null && !mv.wasCleared()) {</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">render(mv, processedRequest,
response);</SPAN><BR style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>.......<BR
style="BACKGROUND-COLOR: rgb(255,255,102)"></SPAN>}<BR>我们很清楚的看到和MVC框架紧密相关的代码,比如如何得到和http请求相对应的执行链,怎样执行执行链和怎样把模型数据展现到视图中去。<BR>先看怎样取得Command对象,对我们来说就是Handler
- 下面是getHandler的代码:<BR>protected HandlerExecutionChain
getHandler(HttpServletRequest request, boolean cache) throws Exception
{<BR><SPAN style="BACKGROUND-COLOR: rgb(255,255,102)">//在ServletContext取得执行链 -
实际上第一次得到它的时候,我们把它放在ServletContext进行了缓存。<BR>HandlerExecutionChain handler
=</SPAN><BR style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">(HandlerExecutionChain)
request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">if (handler != null) {<BR>if (!cache)
{<BR>request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);<BR>}<BR>return
handler;<BR>}<BR>//这里的迭代器迭代的时在initHandlerMapping中载入的上下文所有的HandlerMapping<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">Iterator it =
this.handlerMappings.iterator();</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)">while (it.hasNext())
{<BR>HandlerMapping hm = (HandlerMapping)
it.next();<BR>.......<BR>//这里是实际取得handler的过程,在每个HandlerMapping中建立的映射表进行检索得到请求对应的handler<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)">handler =
hm.getHandler(request);</SPAN><BR
style="BACKGROUND-COLOR: rgb(255,255,102)"><BR>//然后把handler存到ServletContext中去进行缓存<BR><SPAN
style="BACKGROUND-COLOR: rgb(255,255,102)"></SPAN>if (handler != null) {<BR>if
(cache) {<BR>request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE,
handler);<BR>}<BR>return handler;<BR>}<BR>}<BR>return
null;<BR>}<BR>如果在ServletContext中可以取得handler则直接返回,实际上这个handler是缓冲了上次处理的结果 -
总要有第一次把这个handler放到ServletContext中去:<BR>如
果在ServletContext中找不到handler,那就通过持有的handlerMapping生成一个,我们看到它会迭代当前持有的所有的
handlerMapping,因为可以定义不止一个,他们在定义的时候也可以指定顺序,直到找到第一个,然后返回。先找到一个
handlerMapping,然后通过这个handlerMapping返回一个执行链,里面包含了最终的Handler和我们定义的一连串的
Interceptor。具体的我们可以参考上面的SimpleUrlHandlerMapping的代码分析知道getHandler是怎样得到一个
HandlerExecutionChain的。<BR>得到HandlerExecutionChain以后,我们通过HandlerAdapter对这个Handler的合
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -