- 浏览: 756787 次
- 性别:
- 来自: 郑州
文章分类
- 全部博客 (396)
- JAVA (50)
- ORACLE (22)
- HIBERNATE (1)
- SPRING (26)
- STRUTS (4)
- OTHERS (0)
- MYSQL (11)
- Struts2 (16)
- JS (33)
- Tomcat (6)
- DWR (1)
- JQuery (26)
- JBoss (0)
- SQL SERVER (0)
- XML (10)
- 生活 (3)
- JSP (11)
- CSS (5)
- word (1)
- MyEclipse (7)
- JSTL (1)
- JEECMS (2)
- Freemarker (8)
- 页面特效 (1)
- EXT (2)
- Web前端 js库 (2)
- JSON http://www.json.org (3)
- 代码收集 (1)
- 电脑常识 (6)
- MD5加密 (0)
- Axis (0)
- Grails (1)
- 浏览器 (1)
- js调试工具 (1)
- WEB前端 (5)
- JDBC (2)
- PowerDesigner (1)
- OperaMasks (1)
- CMS (1)
- Java开源大全 (2)
- 分页 (28)
- Eclipse插件 (1)
- Proxool (1)
- Jad (1)
- Java反编译 (2)
- 报表 (6)
- JSON (14)
- FCKeditor (9)
- SVN (1)
- ACCESS (1)
- 正则表达式 (3)
- 数据库 (1)
- Flex (3)
- pinyin4j (2)
- IBATIS (3)
- probe (1)
- JSP & Servlet (1)
- 飞信 (0)
- AjaxSwing (0)
- AjaxSwing (0)
- Grid相关 (1)
- HTML (5)
- Guice (4)
- Warp framework (1)
- warp-persist (1)
- 服务器推送 (3)
- eclipse (1)
- JForum (5)
- 工具 (1)
- Python (1)
- Ruby (1)
- SVG (3)
- Joda-Time日期时间工具 (1)
- JDK (3)
- Pushlet (2)
- JSP & Servlet & FTP (1)
- FTP (6)
- 时间与效率 (4)
- 二维码 (1)
- 条码/二维码 (1)
最新评论
-
ctrlc:
你这是从web服务器上传到FTP服务器上的吧,能从用户电脑上上 ...
jsp 往 FTP 上传文件问题 -
annybz:
说的好抽象 为什么代码都有两遍。这个感觉没有第一篇 和第二篇 ...
Spring源代码解析(三):Spring JDBC -
annybz:
...
Spring源代码解析(一):IOC容器 -
jie_20:
你确定你有这样配置做过测试? 请不要转载一些自己没有测试的文档 ...
Spring2.0集成iReport报表技术概述 -
asd51731:
大哥,limit传-1时出错啊,怎么修改啊?
mysql limit 使用方法
下面我们对Spring MVC框架代码进行分析,对于webApplicationContext的相关分析可以参见以前的文档,我们这里着重分析Spring Web MVC框架的实现.我们从分析DispatcherServlet入手:
- //这里是对DispatcherServlet的初始化方法,根据名字我们很方面的 看到对各个Spring MVC主要元素的初始化
- protected void initFrameworkServlet() throws ServletException, BeansException {
- initMultipartResolver();
- initLocaleResolver();
- initThemeResolver();
- initHandlerMappings();
- initHandlerAdapters();
- initHandlerExceptionResolvers();
- initRequestToViewNameTranslator();
- initViewResolvers();
- }
//这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个Spring MVC主要元素的初始化 protected void initFrameworkServlet() throws ServletException, BeansException { initMultipartResolver(); initLocaleResolver(); initThemeResolver(); initHandlerMappings(); initHandlerAdapters(); initHandlerExceptionResolvers(); initRequestToViewNameTranslator(); initViewResolvers(); }
看到注解我们知道,这是DispatcherSerlvet的初始化过程,它是在WebApplicationContext已经存在的情
况下进行的,也就意味着在初始化它的时候,IOC容器应该已经工作了,这也是我们在web.xml中配置Spring的时候,需要把
DispatcherServlet的 load-on-startup的属性配置为2的原因。
对于具体的初始化过程,很容易理解,我们拿
initHandlerMappings()来看看:
- private void initHandlerMappings() throws BeansException {
- if ( this .detectAllHandlerMappings) {
- // 这里找到所有在上下文中定义的 HandlerMapping,同时把他们排序
- // 因为在同一个上下文中可以有不止一个 handlerMapping,所以我们把他们都载入到一个链里进行维护和管理
- Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
- getWebApplicationContext(), HandlerMapping. class , true , false );
- if (!matchingBeans.isEmpty()) {
- this .handlerMappings = new ArrayList(matchingBeans.values());
- // 这里通过order属性来对 handlerMapping来在list中排序
- Collections.sort( this .handlerMappings, new OrderComparator());
- }
- }
- else {
- try {
- Object hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping. class );
- this .handlerMappings = Collections.singletonList(hm);
- }
- catch (NoSuchBeanDefinitionException ex) {
- // Ignore, we'll add a default HandlerMapping later.
- }
- }
- //如果在上下文中没有定义的话,那么我们使用默认的 BeanNameUrlHandlerMapping
- if ( this .handlerMappings == null ) {
- this .handlerMappings = getDefaultStrategies(HandlerMapping. class );
- ........
- }
- }
private void initHandlerMappings() throws BeansException { if (this.detectAllHandlerMappings) { // 这里找到所有在上下文中定义的HandlerMapping,同时把他们排序 // 因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理 Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( getWebApplicationContext(), HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList(matchingBeans.values()); // 这里通过order属性来对handlerMapping来在list中排序 Collections.sort(this.handlerMappings, new OrderComparator()); } } else { try { Object hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } //如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(HandlerMapping.class); ........ } }
怎样获得上下文环境,可以参见我们前面的对IOC容器在web环境中加载的分析。
DispatcherServlet把定义了的所有HandlerMapping都加载了放在一个List里待以后进行使用,这个链的每一个元素都是一个
handlerMapping的配置,而一般每一个handlerMapping可以持有一系列从URL请求到 Spring
Controller的映射,比如SimpleUrl
HandlerMaaping中就定义了一个map来持有这一系列的映射关系。
DisptcherServlet
通过HandlerMapping使得Web应用程序确定一个执行路径,就像我们在HanderMapping中看到的那
样,HandlerMapping只是一个借口:
- public interface HandlerMapping {
- public static final String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE =
- Conventions.getQualifiedAttributeName(HandlerMapping. class , "pathWithinHandlerMapping" );
- //实际上维护一个 HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器
- HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
- }
public interface HandlerMapping { public static final String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = Conventions.getQualifiedAttributeName(HandlerMapping.class, "pathWithinHandlerMapping"); //实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器 HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
他的具体实现只需要实现一个接口方法,而这个接口方法返回的是一个HandlerExecutionChain,实际上就是一个执行链,就
像在Command模式描述的那样,这个类很简单,就是一个持有一个Interceptor链和一个Controller:
- public class HandlerExecutionChain {
- private Object handler;
- private HandlerInterceptor[] interceptors;
- ........
- }
public class HandlerExecutionChain { private Object handler; private HandlerInterceptor[] interceptors; ........ }
而这些Handler和Interceptor需要我们定义HandlerMapping的时候配置好,比如对具体的
SimpleURLHandlerMapping,他要做的就是根据URL映射的方式注册Handler和Interceptor,自己维护一个放映映射
的handlerMap,当需要匹配Http请求的时候需要使用这个表里的信息来得到执行链。这个注册的过程在IOC容器初始化
SimpleUrlHandlerMapping的时候就被完成了,这样以后的解析才可以用到map里的映射信息,这里的信息和bean文件的信息是等价
的,下面是具体的注册过程:
- protected void registerHandlers(Map urlMap) throws BeansException {
- if (urlMap.isEmpty()) {
- logger.warn( "Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping" );
- }
- else {
- //这里迭代在 SimpleUrlHandlerMapping中定义的所有映射元素
- Iterator it = urlMap.keySet().iterator();
- while (it.hasNext()) {
- //这里取得配置的url
- String url = (String) it.next();
- //这里根据url在bean定义中取得对应 的handler
- Object handler = urlMap.get(url);
- // Prepend with slash if not already present.
- if (!url.startsWith( "/" )) {
- url = "/" + url;
- }
- //这里调用 AbstractHandlerMapping中的注册过程
- registerHandler(url, handler);
- }
- }
- }
protected void registerHandlers(Map urlMap) throws BeansException { if (urlMap.isEmpty()) { logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping"); } else { //这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素 Iterator it = urlMap.keySet().iterator(); while (it.hasNext()) { //这里取得配置的url String url = (String) it.next(); //这里根据url在bean定义中取得对应的handler Object handler = urlMap.get(url); // Prepend with slash if not already present. if (!url.startsWith("/")) { url = "/" + url; } //这里调用AbstractHandlerMapping中的注册过程 registerHandler(url, handler); } } }
在AbstractMappingHandler中的注册代码:
- protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
- //试图从handlerMap中取handler,看看是否 已经存在同样的Url映射关系
- Object mappedHandler = this .handlerMap.get(urlPath);
- if (mappedHandler != null ) {
- ........
- }
- //如果是直接用bean名做映射那就直接从容器中取 handler
- if (! this .lazyInitHandlers && handler instanceof String) {
- String handlerName = (String) handler;
- if (getApplicationContext().isSingleton(handlerName)) {
- handler = getApplicationContext().getBean(handlerName);
- }
- }
- //或者使用默认的handler.
- if (urlPath.equals( "/*" )) {
- setDefaultHandler(handler);
- }
- else {
- //把url和handler的对应关系放到 handlerMap中去
- this .handlerMap.put(urlPath, handler);
- ........
- }
- }
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { //试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系 Object mappedHandler = this.handlerMap.get(urlPath); if (mappedHandler != null) { ........ } //如果是直接用bean名做映射那就直接从容器中取handler if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; if (getApplicationContext().isSingleton(handlerName)) { handler = getApplicationContext().getBean(handlerName); } } //或者使用默认的handler. if (urlPath.equals("/*")) { setDefaultHandler(handler); } else { //把url和handler的对应关系放到handlerMap中去 this.handlerMap.put(urlPath, handler); ........ } }
handlerMap是持有的一个HashMap,里面就保存了具体的映射信息:
private final Map handlerMap = new HashMap();
而SimpleUrlHandlerMapping对接口HandlerMapping的实现是这样的,这个getHandler根据在初
始化的时候就得到的映射表来生成DispatcherServlet需要的执行链
- public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- //这里根据request中的参数得到其对应的 handler,具体处理在AbstractUrlHandlerMapping中
- Object handler = getHandlerInternal(request);
- //如果找不到对应的,就使用缺省的handler
- if (handler == null ) {
- handler = this .defaultHandler;
- }
- //如果缺省的也没有,那就没办法了
- if (handler == null ) {
- return null ;
- }
- // 如果handler不是一个具体的handler,那我 们还要到上下文中取
- if (handler instanceof String) {
- String handlerName = (String) handler;
- handler = getApplicationContext().getBean(handlerName);
- }
- //生成一个HandlerExecutionChain,其 中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一 个拦截器组。
- return new HandlerExecutionChain(handler, this .adaptedInterceptors);
- }
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中 Object handler = getHandlerInternal(request); //如果找不到对应的,就使用缺省的handler if (handler == null) { handler = this.defaultHandler; } //如果缺省的也没有,那就没办法了 if (handler == null) { return null; } // 如果handler不是一个具体的handler,那我们还要到上下文中取 if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } //生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。 return new HandlerExecutionChain(handler, this.adaptedInterceptors); }
我们看看具体的handler查找过程:
- protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
- //这里的HTTP Request传进来的参数进行分析,得 到具体的路径信息。
- String lookupPath = this .urlPathHelper.getLookupPathForRequest(request);
- ....... //下面是根据请求信息的查找
- return lookupHandler(lookupPath, request);
- }
- protected Object lookupHandler(String urlPath, HttpServletRequest request) {
- // 如果能够直接能在 SimpleUrlHandlerMapping的映射表中找到,那最好。
- Object handler = this .handlerMap.get(urlPath);
- if (handler == null ) {
- // 这里使用模式来对map中的所有handler 进行匹配,调用了Jre中的Matcher类来完成匹配处理。
- String bestPathMatch = null ;
- for (Iterator it = this .handlerMap.keySet().iterator(); it.hasNext();) {
- String registeredPath = (String) it.next();
- if ( this .pathMatcher.match(registeredPath, urlPath) &&
- (bestPathMatch == null || bestPathMatch.length() <= registeredPath.length())) {
- //这里根据匹配路径找到最象的一个
- handler = this .handlerMap.get(registeredPath);
- bestPathMatch = registeredPath;
- }
- }
- if (handler != null ) {
- exposePathWithinMapping( this .pathMatcher.extractPathWithinPattern(bestPathMatch, urlPath), request);
- }
- }
- else {
- exposePathWithinMapping(urlPath, request);
- }
- //
- return handler;
- }
protected Object getHandlerInternal(HttpServletRequest request) throws Exception { //这里的HTTP Request传进来的参数进行分析,得到具体的路径信息。 String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); .......//下面是根据请求信息的查找 return lookupHandler(lookupPath, request); } protected Object lookupHandler(String urlPath, HttpServletRequest request) { // 如果能够直接能在SimpleUrlHandlerMapping的映射表中找到,那最好。 Object handler = this.handlerMap.get(urlPath); if (handler == null) { // 这里使用模式来对map中的所有handler进行匹配,调用了Jre中的Matcher类来完成匹配处理。 String bestPathMatch = null; for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) { String registeredPath = (String) it.next(); if (this.pathMatcher.match(registeredPath, urlPath) && (bestPathMatch == null || bestPathMatch.length() <= registeredPath.length())) { //这里根据匹配路径找到最象的一个 handler = this.handlerMap.get(registeredPath); bestPathMatch = registeredPath; } } if (handler != null) { exposePathWithinMapping(this.pathMatcher.extractPathWithinPattern(bestPathMatch, urlPath), request); } } else { exposePathWithinMapping(urlPath, request); } // return handler; }
我们可以看到,总是在handlerMap这个HashMap中找,当然如果直接找到最好,如果找不到,就看看是不是能通过Match
Pattern的模式找,我们一定还记得在配置HnaderMapping的时候是可以通过ANT语法进行配置的,其中的处理就在这里。
这样可
以清楚地看到整个HandlerMapping的初始化过程 - 同时,我们也看到了一个具体的handler映射是怎样被存储和查找的 -
这里生成一个ExecutionChain来储存我们找到的handler和在定义bean的时候定义的Interceptors.
让我们回到
DispatcherServlet,初始化完成以后,实际的对web请求是在doService()方法中处理的,我们知道
DispatcherServlet只是一个普通的Servlet:
- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
- .......
- //这里把属性信息进行保存
- Map attributesSnapshot = null ;
- if (WebUtils.isIncludeRequest(request)) {
- logger.debug( "Taking snapshot of request attributes before include" );
- attributesSnapshot = new HashMap();
- Enumeration attrNames = request.getAttributeNames();
- while (attrNames.hasMoreElements()) {
- String attrName = (String) attrNames.nextElement();
- if ( this .cleanupAfterInclude || attrName.startsWith(DispatcherServlet. class .getName())) {
- 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());
- try {
- //这里使实际的处理入口
- doDispatch(request, response);
- }
- finally {
- // Restore the original attribute snapshot, in case of an include.
- if (attributesSnapshot != null ) {
- restoreAttributesAfterInclude(request, attributesSnapshot);
- }
- }
- }
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { ....... //这里把属性信息进行保存 Map attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { logger.debug("Taking snapshot of request attributes before include"); attributesSnapshot = new HashMap(); Enumeration attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DispatcherServlet.class.getName())) { 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()); try { //这里使实际的处理入口 doDispatch(request, response); } finally { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } }
我们看到,对于请求的处理实际上是让doDispatch()来完成的 - 这个方法很长,但是过程很简单明了:
- protected void doDispatch( final HttpServletRequest request, HttpServletResponse response) throws Exception {
- HttpServletRequest processedRequest = request;
- //这是从handlerMapping中得到的执行链
- HandlerExecutionChain mappedHandler = null ;
- int interceptorIndex = - 1 ;
- ........
- try {
- //我们熟悉的ModelAndView开始出现了。
- ModelAndView mv = null ;
- try {
- processedRequest = checkMultipart(request);
- // 这是我们得到handler的过程
- mappedHandler = getHandler(processedRequest, false );
- if (mappedHandler == null || mappedHandler.getHandler() == null ) {
- noHandlerFound(processedRequest, response);
- return ;
- }
- // 这里取出执行链中的 Interceptor进行前处理
- if (mappedHandler.getInterceptors() != null ) {
- for ( int i = 0 ; i < mappedHandler.getInterceptors().length; i++) {
- HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
- if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null );
- return ;
- }
- interceptorIndex = i;
- }
- }
- //在执行handler之前,用 HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的。
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- // 这里取出执行链中的 Interceptor进行后处理
- if (mappedHandler.getInterceptors() != null ) {
- for ( int i = mappedHandler.getInterceptors().length - 1 ; i >= 0 ; i--) {
- HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
- interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
- }
- }
- }
- ........
- // Did the handler return a view to render?
- //这里对视图生成进行处理
- if (mv != null && !mv.wasCleared()) {
- render(mv, processedRequest, response);
- }
- .......
- }
protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; //这是从handlerMapping中得到的执行链 HandlerExecutionChain mappedHandler = null; int interceptorIndex = -1; ........ try { //我们熟悉的ModelAndView开始出现了。 ModelAndView mv = null; try { processedRequest = checkMultipart(request); // 这是我们得到handler的过程 mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // 这里取出执行链中的Interceptor进行前处理 if (mappedHandler.getInterceptors() != null) { for (int i = 0; i < mappedHandler.getInterceptors().length; i++) { HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i]; if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); return; } interceptorIndex = i; } } //在执行handler之前,用HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的。 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 这里取出执行链中的Interceptor进行后处理 if (mappedHandler.getInterceptors() != null) { for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i--) { HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i]; interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); } } } ........ // Did the handler return a view to render? //这里对视图生成进行处理 if (mv != null && !mv.wasCleared()) { render(mv, processedRequest, response); } ....... }
我们很清楚的看到和MVC框架紧密相关的代码,比如如何得到和http请求相对应的执行链,怎样执行执行链和怎样把模型数据展现到视图中
去。
先看怎样取得Command对象,对我们来说就是Handler - 下面是getHandler的代码:
- protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
- //在ServletContext取得执行链 - 实际上第一次 得到它的时候,我们把它放在ServletContext进行了缓存。
- HandlerExecutionChain handler =
- (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
- if (handler != null ) {
- if (!cache) {
- request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
- }
- return handler;
- }
- //这里的迭代器迭代的时在 initHandlerMapping中载入的上下文所有的HandlerMapping
- Iterator it = this .handlerMappings.iterator();
- while (it.hasNext()) {
- HandlerMapping hm = (HandlerMapping) it.next();
- .......
- //这里是实际取得handler的过程,在每个 HandlerMapping中建立的映射表进行检索得到请求对应的handler
- handler = hm.getHandler(request);
- //然后把handler存到 ServletContext中去进行缓存
- if (handler != null ) {
- if (cache) {
- request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);
- }
- return handler;
- }
- }
- return null ;
- }
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception { //在ServletContext取得执行链 - 实际上第一次得到它的时候,我们把它放在ServletContext进行了缓存。 HandlerExecutionChain handler = (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE); if (handler != null) { if (!cache) { request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE); } return handler; } //这里的迭代器迭代的时在initHandlerMapping中载入的上下文所有的HandlerMapping Iterator it = this.handlerMappings.iterator(); while (it.hasNext()) { HandlerMapping hm = (HandlerMapping) it.next(); ....... //这里是实际取得handler的过程,在每个HandlerMapping中建立的映射表进行检索得到请求对应的handler handler = hm.getHandler(request); //然后把handler存到ServletContext中去进行缓存 if (handler != null) { if (cache) { request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler); } return handler; } } return null; }
如果在ServletContext中可以取得handler则直接返回,实际上这个handler是缓冲了上次处理的结果 -
总要有第一次把这个handler放到ServletContext中去:
如果在ServletContext中找不到handler,那就通
过持有的handlerMapping生成一个,我们看到它会迭代当前持有的所有的
handlerMapping,因为可以定义不止一个,他们在定义的时候也可以指定顺序,直到找到第一个,然后返回。先找到一个
handlerMapping,然后通过这个handlerMapping返回一个执行链,里面包含了最终的Handler和我们定义的一连串的
Interceptor。具体的我们可以参考上面的SimpleUrlHandlerMapping的代码分析知道getHandler是怎样得到一个
HandlerExecutionChain的。
得到HandlerExecutionChain以后,我们通过HandlerAdapter
对这个Handler的合法性进行判断:
- protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
- Iterator it = this .handlerAdapters.iterator();
- while (it.hasNext()) {
- //同样对持有的所有adapter进行匹配
- HandlerAdapter ha = (HandlerAdapter) it.next();
- if (ha.supports(handler)) {
- return ha;
- }
- }
- ........
- }
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { Iterator it = this.handlerAdapters.iterator(); while (it.hasNext()) { //同样对持有的所有adapter进行匹配 HandlerAdapter ha = (HandlerAdapter) it.next(); if (ha.supports(handler)) { return ha; } } ........ }
通过判断,我们知道这个handler是不是一个Controller接口的实现,比如对于具体的HandlerAdapter -
SimpleControllerHandlerAdapter:
- public class SimpleControllerHandlerAdapter implements HandlerAdapter {
- public boolean supports(Object handler) {
- return (handler instanceof Controller);
- }
- .......
- }
public class SimpleControllerHandlerAdapter implements HandlerAdapter { public boolean supports(Object handler) { return (handler instanceof Controller); } ....... }
简单的判断一下handler是不是实现了Controller接口。这也体现了一种对配置文件进行验证的机制。
让我们再回到
DispatcherServlet看到代码:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这个就是对handle的具体调用!相当于Command模式里的Command.execute();理所当然的返回一个
ModelAndView,下面就是一个对View进行处理的过程:
if (mv != null && !mv.wasCleared()) { render(mv, processedRequest, response); }
调用的是render方法:
- protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
- throws Exception {response.setLocale(locale);
- View view = null ;
- //这里把默认的视图放到ModelAndView中去。
- if (!mv.hasView()) {
- mv.setViewName(getDefaultViewName(request));
- }
- if (mv.isReference()) {
- // 这里对视图名字进行解析
- view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
- .......
- }
- else {
- // 有可能在ModelAndView里已经直接 包含了View对象,那我们就直接使用。
- view = mv.getView();
- ........
- }
- //得到具体的View对象以后,我们用它来生成视图。
- view.render(mv.getModelInternal(), request, response);
- }
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {response.setLocale(locale); View view = null; //这里把默认的视图放到ModelAndView中去。 if (!mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } if (mv.isReference()) { // 这里对视图名字进行解析 view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); ....... } else { // 有可能在ModelAndView里已经直接包含了View对象,那我们就直接使用。 view = mv.getView(); ........ } //得到具体的View对象以后,我们用它来生成视图。 view.render(mv.getModelInternal(), request, response); }
从整个过程我们看到先在ModelAndView中寻找视图的逻辑名,如果找不到那就使用缺省的视图,如果能够找到视图的名字,那就对他进
行解析得到实际的需要使用的视图对象。还有一种可能就是在ModelAndView中已经包含了实际的视图对象,这个视图对象是可以直接使用的。
不
管怎样,得到一个视图对象以后,通过调用视图对象的render来完成数据的显示过程,我们可以看看具体的JstlView是怎样实现的,我们在
JstlView的抽象父类 AbstractView中找到render方法:
- public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
- ......
- // 这里把所有的相关信息都收集到一个Map里
-
Map mergedModel =
new
HashMap(
this
评论
2 楼 kensunhu 2012-04-13整个主线是串起来了,MVC: request=>mapping controller=>handle request=>render view=>response. 同一份代码为什么copy两次呢?加深记忆?1 楼 waainli 2012-03-26这个源代码是Spring什么版本的啊?写的挺好的。发表评论
-
Spring--quartz中cronExpression配置说明
2011-12-02 18:28 0quartz中cronExpression配置说明 字段 ... -
使用Spring的jdbcTemplate进一步简化JDBC操作
2011-12-02 09:20 1268先看applicationContext.xml配置文件: ... -
Spring MVC:使用SimpleUrlHandlerMapping的一个简单例子
2011-12-01 11:26 969实现一个控制器ShirdrnCon ... -
最简单的Spring MVC入门示例
2010-05-19 14:29 1532应一位朋友的要求,写一个最简单的spring示例,使用s ... -
Spring源代码解析(十):Spring Acegi框架授权的实现
2010-03-18 12:48 1527我们从FilterSecurityIntercep ... -
Spring源代码解析(九):Spring Acegi框架鉴权的实现
2010-03-18 12:47 1512简单分析一下Spring Acegi的源代码实现: Ser ... -
Spring源代码解析(八):Spring驱动Hibernate的实现
2010-03-18 12:41 1454O/R工具出现之后,简化了许多复杂的信息持久化的开发。Spri ... -
Spring源代码解析(七):Spring AOP中对拦截器调用的实现
2010-03-18 12:40 1425前面我们分析了Spring AOP实现中得到Proxy对象的过 ... -
Spring源代码解析(六):Spring声明式事务处理
2010-03-18 12:37 1105我们看看Spring中的事务处理的代码,使用Spring管理事 ... -
Spring源代码解析(五):Spring AOP获取Proxy
2010-03-18 12:36 1328下面我们来看看Spring的AOP的一些相关代码是怎么得到Pr ... -
Spring源代码解析(三):Spring JDBC
2010-03-18 12:33 1702下面我们看看Spring JDBC相关的实现, 在Spri ... -
Spring源代码解析(二):IoC容器在Web容器中的启动
2010-03-18 12:32 1452上面我们分析了IOC容器本身的实现,下面我们看看在典型的web ... -
Spring源代码解析(一):IOC容器
2010-03-18 12:30 2677在Spring中,IOC容器的重要地位我们就不多说了,对于Sp ... -
使用Spring的JdbcTemplate和BeanPropertyRowMapper完成的JDBC
2010-03-18 12:08 2250先道要加上两个包:Spring2.5下面的: spring. ... -
使用Spring的SimpleJdbcTemplate完成DAO操作
2010-03-18 12:06 1513l SimpleJdbcTemplate内部包含了 ... -
使用Spring的NamedParameterJdbcTemplate完成DAO操作
2010-03-18 12:05 1435NamedParameterJdbcTemplate内部包含了 ... -
Spring in Action 学习笔记—第四章 征服数据库(转)
2010-03-18 12:03 1258Spring2.0正式版(http://www.springf ... -
Spring管理JDBC连接
2010-03-18 11:59 1696在Spring中,JdbcTemplate是经常被使用的类来帮 ... -
Spring JDBC数据库操作类
2010-03-18 09:26 16491.JdbcTemplate 在Spring中, ... -
Spring JdbcTemplate 批量插入或更新操作
2010-03-18 09:19 5288用 JdbcTemplate 进行批量插入或更新操作 ...
相关推荐
Spring源代码解析4:Spring MVC .doc Spring源代码解析5:Spring AOP获取Proxy .doc Spring源代码解析6:Spring声明式事务处理 .doc Spring源代码解析7:Spring AOP中对拦截器调用的实现 .doc Spring源代码解析8:...
Spring源代码解析4:Spring MVC ;Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动...
Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务处理 Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):...
Spring源代码解析4:Spring MVC ;Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动...
在Spring源代码解析的第四部分中,我们将重点关注DispatcherServlet的初始化过程,它是Spring MVC的核心组件。 DispatcherServlet是一个特殊的Servlet,它负责接收HTTP请求,并根据请求映射到相应的处理器...
Spring源代码解析(四):Spring MVC.doc Spring源代码解析(五):Spring AOP获取Proxy.doc Spring源代码解析(六):Spring声明式事务处理.doc Spring源代码解析(七):Spring AOP中对拦截器调用的实现.doc Spring源...
spring mvc4.1.4 源代码 spring mvc4.1.4 源代码spring mvc4.1.4 源代码spring mvc4.1.4 源代码spring mvc4.1.4 源代码
Spring MVC深入解析 Spring MVC是一个基于模型-视图-控制器(MVC)模式的Web应用程序框架,是Spring Framework的一部分。它提供了一个灵活的方式来构建Web应用程序,使得开发者可以轻松地创建复杂的Web应用程序。 ...
《Spring源代码解析》 Spring框架作为Java领域最流行的开源框架之一,它的设计思想和实现方式一直是广大开发者关注的焦点。深入理解Spring的源代码,能够帮助我们更好地掌握其工作原理,提高我们的开发效率和代码...
《看透Spring MVC源代码分析与实践》这本书深入剖析了Spring MVC这一强大的Web应用程序开发框架。Spring MVC作为Spring框架的一部分,被广泛应用于企业级Java应用中,它为开发者提供了构建可扩展、模块化且易于维护...
书名:《看透Spring MVC:源代码分析与实践》 作者:韩路彪 Spring MVC相关的源码分析
看透Spring MVC:源代码分析与实践
这个“Spring源代码解析”压缩包文件很可能是对Spring框架内部实现原理的详细分析,帮助开发者深入理解其工作机制。 在Spring框架中,依赖注入是核心概念之一,它允许开发者在运行时通过容器来管理对象的创建和依赖...
赠送源代码:spring-webmvc-5.0.8.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-webmvc-5.0.8.RELEASE.pom; 包含翻译后的API文档:spring-webmvc-5.0.8.RELEASE-javadoc-API文档-中文(简体)版.zip; Maven...
《看透Spring MVC:源代码分析与实践》是一本深入探讨Spring MVC框架核心机制的书籍。通过对源代码的解析,读者可以深入了解这个广泛使用的Java Web开发框架的工作原理,从而更好地运用和优化自己的项目。该书提供了...
《Java EE企业级应用开发教程Spring+Spring MVC+MyBatis》是一本深入探讨Java企业级应用程序开发的书籍,源代码包含多个章节的实例,旨在帮助读者理解和掌握使用Spring、Spring MVC和MyBatis框架进行实际开发的关键...
这份【面试资料】-(机构内训资料)看透Spring MVC源代码分析与实践.zip文件很可能是为了帮助求职者准备相关面试问题而设计的,包含了对Spring MVC工作原理、关键组件和源码解读的详尽解析。 1. **Spring MVC基本...