⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 java开源笔记:spring源代码解析.htm

📁 springioc部分最新的分析
💻 HTM
📖 第 1 页 / 共 5 页
字号:
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 &amp;&amp; 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) &amp;&amp;<BR>(bestPathMatch == 
null || bestPathMatch.length() &lt;= 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 &lt; 
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 &gt;= 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 &amp;&amp; !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 + -