收藏私塾在线
 

欢迎您来到私塾在线网!   

请登录! 

免费注册 


zhang的笔记
状态: 离线
人气:5086801
访问用户量:4227
笔记经验:
总积分:261656
级别:VIP5
搜索本笔记
ta的交流分类
ta的交流主题贴(544)
ta的所有交流贴(1049)
ta的全部笔记
全部笔记(255)
未分类笔记(1)
Java Web(9)
并发实践(1)
课程问题(0)
Java(22)
架构(1)
缓存(5)
JavaEE(0)
JVM(12)
跟我学spring3(68)
Spring Sec……(43)
Spring 3.x……(25)
Spring Sec……(20)
跟开涛学Spring……(17)
深入剖析Spring……(18)
性能调优(10)
前端(2)
Tomcat源码解读(1)
spring sec……(0)
存档
2014-01(7)
2013-12(10)
2012-10(4)
2012-09(2)
2012-08(31)
2012-07(10)
2012-06(5)
2012-05(41)
2012-04(3)
2012-03(41)
2012-02(54)
2011-11(17)
2011-10(30)

2012-08-06 16:01:05
深入剖析Spring Web源码(十一) - 处理器映射,处理器适配器以及处理器的实现 - 处理器映射的实现架构
浏览(3977)|评论(0)   交流分类:Java|笔记分类: 深入剖析Spring……

 

2.2.2.1 处理器映射的实现架构

 

作为总控制器的派遣器Servlet首先会轮询处理器映射模块,查找能够处理当前请求的处理器,处理器映射模块根据当前请求的URL返回简单的控制器类型,注解控制器类型或者远程调用处理器类型。前一小节中,我们根据流程的实现分析了Bean名URL处理器映射(BeanNameUrlHandlerMapping)和缺省注解处理器映射(DefaultAnnotationHandlerMapping)。事实上,在处理器映射的实现体系结构中还有其他的实现,用来实现根据不同的规则查找相应的处理器的逻辑。不同层次的处理器映射的实现,无论是抽象类还是实现类,都关联着特殊而又完整的逻辑。如下类图所示,

 

 

图表 4‑29

 

上一节流程分析中讨论的Bean名URL处理器映射(BeanNameUrlHandlerMapping)和缺省注解处理器映射(DefaultAnnotationHandlerMapping),他们是经常使用到的处理器映射的实现,下面我们介绍所有的处理器映射的具体实现类的逻辑功能。

 

l         Bean名URL处理器映射(BeanNameUrlHandlerMapping)

 

这个实现类通过识别Web应用程序环境中以URL为名字声明的Bean为处理器。URL是通过以斜线(/)开头的并且以斜线(/)分隔的字符串。然后,使用Bean名中声明的URL和请求的URL进行匹配,如果匹配成功,则使用匹配的Bean作为处理器返回。

 

l         缺省注解处理器映射(DefaultAnnotationHandlerMapping)

 

这个实现类通过声明在Web应用程序环境中Bean类型中的请求映射注解(@RequestMapping)来注册处理器映射的。请求映射注解声明有匹配请求URL所用的URL Pattern。然后,使用方法级别的请求映射注解中声明的URL Pattern和类型级别的请求映射注解中声明的URL Pattern结合并且匹配请求的URL,如果匹配成功,则使用匹配的Bean作为处理器返回。

 

l         控制器类名处理器映射(ControllerClassNameHandlerMapping)

 

这个实现类通过声明在Web应用程序环境中的控制器类型来注册处理器映射的。它从控制器的类型转换出控制器所服务的URL Pattern。这个转换规则是,把点号分割的具有包前缀的类名替换成斜线(/)分割的具有包前缀的字符串,再加上前缀和后缀构成URL Pattern,然后,使用得到的Pattern匹配请求的URL,如果匹配成功,则使用匹配的Bean作为处理器返回。

 

l         控制器Bean名处理器映射(ControllerBeanNameHandlerMapping)

 

这个实现类通过声明在Web应用程序环境中的控制器类型来注册处理器映射的。它从控制器的Bean名字转换出控制器所服务的URL Pattern。这个转换规则是,把Bean名字加上前缀和后缀构成URL Pattern,然后,使用得到的Pattern匹配请求的URL,如果匹配成功,则使用匹配的Bean作为处理器返回。

 

l         简单URL处理器映射(SimpleUrlHandlerMapping)

 

这个实现类通过配置一套URL Pattern到处理器的映射而实现的。它使用配置的映射中的URL Pattern匹配请求中的URL,如果匹配成功,则使用匹配URL Pattern映射的Bean作为处理器返回。

 

我们看到具体的实现类并不是直接实现处理器映射接口的,而是通过一系列的抽象类的实现最终完成的,在每个抽象类的实现层次上完成不同的独立的逻辑功能。下面我们分析这些抽象类和实现他们的具体实现类是如何分工并且最终完成必要的业务逻辑的。

 

l         抽象处理器映射(AbstractHandlerMapping)

 

抽象处理器映射是处理器映射实现中的最底层的实现,它直接实现处理器映射接口,并且继承Web应用程序环境支持对象。它提供了配置缺省处理器以及应用到所有处理器上的处理器拦截器的功能。

 

它把具体如何取得一个处理器抽象并且留给子类进行特殊化的实现。

 

l         抽象URL处理器映射(AbstractUrlHandlerMapping)

 

抽象URL处理器映射继承自抽象处理器映射,实现了取得一个处理器的抽象方法,提供了功能根据URL进行匹配处理器的功能。也提供了根据URL查找应用在处理器上特殊的拦截器。并且提供了方法实现注册URL到处理器的映射。

 

如何获得URL到处理器的映射的逻辑留给子类进行完成。

 

简单URL处理器映射就是通过应用程序环境中Bean串联配置直接注射URL到处理器映射来实现抽象URL处理器映射的。

 

l         抽象探测URL处理器映射(AbstractDetectingUrlHandlerMapping)

 

抽象探测URL处理器映射通过一定的规则在Web应用程序环境中自动发现URL到处理器的映射。

 

使用什么样的规则在Web应用程序环境中自动发现URL到处理器的映射并没有直接实现,因为这会有很多的映射规则,并且根据需求可以自由扩展。这个规则留给子类进行实现。

 

Bean名URL处理器映射就是根据把Bean名声明作为URL来发现处理器的。而缺省注解处理器映射是根据声明在控制器中的请求映射注解中包含的URL Pattern信息来解析处理器的。

 

l         抽象控制器URL处理器映射(AbstractControllerUrlHandlerMapping)

 

这是抽象探测URL处理器映射的另外一个实现,这个实现也是一个抽象的实现,它是通过在Bean环境中找到合适的控制器类型,根据一定的规则将控制器类型映射到一个或者多个URL Pattern来实现的。

 

它有两个具体的实现类,控制器类名处理器映射是根据类名解析出映射的URL Pattern。而控制器Bean名处理器映射则是根据控制器在Web应用程序环境中声明的Bean名映射到URL Pattern的。

 

在上一节的分析中,我们已经对Bean名URL处理器映射(BeanNameUrlHandlerMapping)和缺省注解处理器映射(DefaultAnnotationHandlerMapping)以及他们的父类进行分析。下面我们将对剩余的其他的类进行代码分析,首先回顾一下抽象探测URL处理器映射的实现,如下代码注释,

 

 

[java] view plaincopy
  1. protected abstract String[] determineUrlsForHandler(String beanName);  

 

 

它留下了一个抽象方法,对于Web应用程序环境中的每一个Bean,都将使用此方法找到Bean所映射到的URL Pattern。子类需要根据具体的映射规则来实现这个方法。除了上一节中分析的Bean名URL处理器映射和缺省注解处理器映射实现了这个方法外,存在另外一套根据控制器类型映射的实现。这套根据控制器类型映射的实现包含一个抽象实现和两个具体实现,抽象实现是抽象控制器处理器映射。如下代码所示,

 

 

[java] view plaincopy
  1. public abstract class AbstractControllerUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping  {  
  2.   
  3.     // 通过控制器接口类型或者控制器注解类型查找简单控制器和注解控制器的实用类  
  4.     private ControllerTypePredicate predicate = new AnnotationControllerTypePredicate();  
  5.   
  6.     // 声明的包中的控制器不会作为处理器进行注册  
  7.     private Set<String> excludedPackages = Collections.singleton("org.springframework.web.servlet.mvc");  
  8.   
  9.     // 声明的类不会作为处理器进行注册  
  10.     private Set<Class> excludedClasses = Collections.emptySet();  
  11.   
  12.     // 实现根据Bean映射出URL的逻辑  
  13.     @Override  
  14.     protected String[] determineUrlsForHandler(String beanName) {  
  15.         // 取得Bean的类型  
  16.         Class beanClass = getApplicationContext().getType(beanName);  
  17.           
  18.         // 判断是否Bean可以作为控制器处理器  
  19.         if (isEligibleForMapping(beanName, beanClass)) {  
  20.             // 根据Bean名字或者类型名映射出URL的逻辑  
  21.             return buildUrlsForHandler(beanName, beanClass);  
  22.         }  
  23.         else {  
  24.             return null;  
  25.         }  
  26.     }  
  27.   
  28.   
  29.     protected boolean isEligibleForMapping(String beanName, Class beanClass) {  
  30.         // 如果Bean类型是空,则不映射此Bean  
  31.         if (beanClass == null) {  
  32.             if (logger.isDebugEnabled()) {  
  33.                 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +  
  34.                         "because its bean type could not be determined");  
  35.             }  
  36.             return false;  
  37.         }  
  38.           
  39.         // 如果Bean的包配置为排除包,则不映射此Bean  
  40.         if (this.excludedClasses.contains(beanClass)) {  
  41.             if (logger.isDebugEnabled()) {  
  42.                 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +  
  43.                         "because its bean class is explicitly excluded: " + beanClass.getName());  
  44.             }  
  45.             return false;  
  46.         }  
  47.           
  48.         // 如果Bean的包配置为排除类,则不映射此Bean  
  49.         String beanClassName = beanClass.getName();  
  50.         for (String packageName : this.excludedPackages) {  
  51.             if (beanClassName.startsWith(packageName)) {  
  52.                 if (logger.isDebugEnabled()) {  
  53.                     logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +  
  54.                             "because its bean class is defined in an excluded package: " + beanClass.getName());  
  55.                 }  
  56.                 return false;  
  57.             }  
  58.         }  
  59.           
  60.         // 必须是控制器类型,才映射作为控制器处理器  
  61.         return isControllerType(beanClass);  
  62.     }  
  63.   
  64.   
  65.     protected boolean isControllerType(Class beanClass) {  
  66.         return this.predicate.isControllerType(beanClass);  
  67.     }  
  68.   
  69.   
  70.     protected boolean isMultiActionControllerType(Class beanClass) {  
  71.         return this.predicate.isMultiActionControllerType(beanClass);  
  72.     }  
  73.   
  74.   
  75.     // 子类可以选择根据Bean名字还是根据Bean类来映射URL Pattern  
  76.     protected abstract String[] buildUrlsForHandler(String beanName, Class beanClass);  
  77.   
  78. }  

  

 

抽象控制器处理器映射有两个实现,一个是根据Bean名字映射到URL Pattern的实现,另外一个是根据Bean的类型映射到URL Pattern的实现。

 

以下是控制器Bean名处理器映射(ControllerBeanNameHandlerMapping)的代码注释,

 

 

[java] view plaincopy
  1. public class ControllerBeanNameHandlerMapping extends AbstractControllerUrlHandlerMapping {  
  2.   
  3.     private String urlPrefix = "";  
  4.   
  5.     private String urlSuffix = "";  
  6.   
  7.     @Override  
  8.     protected String[] buildUrlsForHandler(String beanName, Class beanClass) {  
  9.         List<String> urls = new ArrayList<String>();  
  10.           
  11.         // 根据Bean名产生URL Pattern  
  12.         urls.add(generatePathMaping(beanName));  
  13.           
  14.         // 对于Bean名的别名,以同样的规则产生URL Pattern  
  15.         String[] aliases = getApplicationContext().getAliases(beanName);  
  16.         for (String alias : aliases) {  
  17.             urls.add(generatePathMapping(alias));  
  18.         }  
  19.           
  20.         // 返回URL Pattern数组  
  21.         return StringUtils.toStringArray(urls);  
  22.     }  
  23.   
  24.     /** 
  25.      * Prepends a '/' if required and appends the URL suffix to the name. 
  26.      */  
  27.     protected String generatePathMapping(String beanName) {  
  28.         // 如果bean名不是以斜线(/)开头,则增加斜线(/)  
  29.         String name = (beanName.startsWith("/") ? beanName : "/" + beanName);  
  30.         StringBuilder path = new StringBuilder();  
  31.           
  32.         // 添加前缀  
  33.         if (!name.startsWith(this.urlPrefix)) {  
  34.             path.append(this.urlPrefix);  
  35.         }  
  36.           
  37.         path.append(name);  
  38.           
  39.         // 添加后缀  
  40.         if (!name.endsWith(this.urlSuffix)) {  
  41.             path.append(this.urlSuffix);  
  42.         }  
  43.         return path.toString();  
  44.     }  
  45.   
  46. }  

 

 

以下是控制器类名处理器映射(ControllerClassNameHandlerMapping)的代码注释,

 

 

[java] view plaincopy
  1. public class ControllerClassNameHandlerMapping extends AbstractControllerUrlHandlerMapping {  
  2.     // 控制器名的后缀  
  3.     private static final String CONTROLLER_SUFFIX = "Controller";  
  4.   
  5.     // 通过类型映射的路径是否保持大写字母的存在  
  6.     private boolean caseSensitive = false;  
  7.   
  8.     private String pathPrefix;  
  9.   
  10.     private String basePackage;  
  11.   
  12.     public void setPathPrefix(String prefixPath) {  
  13.         this.pathPrefix = prefixPath;  
  14.           
  15.         // 一个路径应该保证有斜线(/)开头,但是没有斜线(/)结尾  
  16.         if (StringUtils.hasLength(this.pathPrefix)) {  
  17.             if (!this.pathPrefix.startsWith("/")) {  
  18.                 this.pathPrefix = "/" + this.pathPrefix;  
  19.             }  
  20.             if (this.pathPrefix.endsWith("/")) {  
  21.                 this.pathPrefix = this.pathPrefix.substring(0, this.pathPrefix.length() - 1);  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.   
  27.     public void setBasePackage(String basePackage) {  
  28.         this.basePackage = basePackage;  
  29.           
  30.         // 设置缺省的包前缀  
  31.         if (StringUtils.hasLength(this.basePackage) && !this.basePackage.endsWith(".")) {  
  32.             this.basePackage = this.basePackage + ".";  
  33.         }  
  34.     }  
  35.   
  36.     @Override  
  37.     protected String[] buildUrlsForHandler(String beanName, Class beanClass) {  
  38.         // 仅仅使用类名进行映射  
  39.         return generatePathMappings(beanClass);  
  40.     }  
  41.   
  42.     protected String[] generatePathMappings(Class beanClass) {  
  43.         // 产生路径前缀  
  44.         StringBuilder pathMapping = buildPathPrefix(beanClass);  
  45.           
  46.         // 取得不包含包名的类名  
  47.         String className = ClassUtils.getShortName(beanClass);  
  48.           
  49.         // 如果以控制器后缀(Controller)结尾,则移除控制器后缀  
  50.         String path = (className.endsWith(CONTROLLER_SUFFIX) ?  
  51.                 className.substring(0, className.lastIndexOf(CONTROLLER_SUFFIX)) : className);  
  52.           
  53.         if (path.length() > 0) {  
  54.             // 如果保持路径大小写,则把类名的第一个字符小写  
  55.             if (this.caseSensitive) {  
  56.                 pathMapping.append(path.substring(0, 1).toLowerCase()).append(path.substring(1));  
  57.             }  
  58.             // 否则使所有路径字符变成小写  
  59.             else {  
  60.                 pathMapping.append(path.toLowerCase());  
  61.             }  
  62.         }  
  63.           
  64.         // 如果是多行为控制器类型,则加URL本身和所有的子URL  
  65.         if (isMultiActionControllerType(beanClass)) {  
  66.             return new String[] {pathMapping.toString(), pathMapping.toString() + "/*"};  
  67.         }  
  68.         // 否则只加URL本身  
  69.         else {  
  70.             return new String[] {pathMapping.toString() + "*"};  
  71.         }  
  72.     }  
  73.   
  74.   
  75.     private StringBuilder buildPathPrefix(Class beanClass) {  
  76.         StringBuilder pathMapping = new StringBuilder();  
  77.           
  78.         // 第一部分是路径前缀  
  79.         if (this.pathPrefix != null) {  
  80.             pathMapping.append(this.pathPrefix);  
  81.             pathMapping.append("/");  
  82.         }  
  83.         else {  
  84.             pathMapping.append("/");  
  85.         }  
  86.           
  87.         // 第二部分是包名中逗点替换成斜线的结果  
  88.         if (this.basePackage != null) {  
  89.             String packageName = ClassUtils.getPackageName(beanClass);  
  90.             if (packageName.startsWith(this.basePackage)) {  
  91.                 String subPackage = packageName.substring(this.basePackage.length()).replace('.', '/');  
  92.                 pathMapping.append(this.caseSensitive ? subPackage : subPackage.toLowerCase());  
  93.                 pathMapping.append("/");  
  94.             }  
  95.         }  
  96.         return pathMapping;  
  97.     }  
  98.   
  99. }  

 

 

抽象URL处理器映射有另外一个具体实现简单URL处理器映射,它根据配置的URL Pattern到处理器的映射来查找处理器,如下代码所示,

 

 

[java] view plaincopy
  1. public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {  
  2.       
  3.     private final Map<String, Object> urlMap = new HashMap<String, Object>();  
  4.   
  5.     // 通过属性配置URL到Bean名的映射  
  6.     public void setMappings(Properties mappings) {  
  7.         CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);  
  8.     }  
  9.   
  10.     // 配置URL到Bean的映射  
  11.     public void setUrlMap(Map<String, ?> urlMap) {  
  12.         this.urlMap.putAll(urlMap);  
  13.     }  
  14.   
  15.     public Map<String, ?> getUrlMap() {  
  16.         return this.urlMap;  
  17.     }  
  18.   
  19.     @Override  
  20.     public void initApplicationContext() throws BeansException {  
  21.         super.initApplicationContext();  
  22.         // 初始化的时候注册处理器  
  23.         registerHandlers(this.urlMap);  
  24.     }  
  25.   
  26.     protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {  
  27.         // 如果配置的处理器映射为空,则警告  
  28.         if (urlMap.isEmpty()) {  
  29.             logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");  
  30.         }  
  31.         else {  
  32.             // 对于没一个配置的URL到处理器的映射,如果URL不是以斜线(/)开头,则追加斜线开头,则注册处理器  
  33.             for (Map.Entry<String, Object> entry : urlMap.entrySet()) {  
  34.                 String url = entry.getKey();  
  35.                 Object handler = entry.getValue();  
  36.                 // Prepend with slash if not already present.  
  37.                 if (!url.startsWith("/")) {  
  38.                     url = "/" + url;  
  39.                 }  
  40.                 // Remove whitespace from handler bean name.  
  41.                 if (handler instanceof String) {  
  42.                     handler = ((String) handler).trim();  
  43.                 }  
  44.                 registerHandler(url, handler);  
  45.             }  
  46.         }  
  47.     }  
  48.   
  49. }  

 

http://blog.csdn.net/robertleepeak/article/details/5915344

精品视频课程推荐

Java数据结构和算法精讲版
本课程专注于数据结构和算法的内容,使用Java来进行代码示例,不空洞的讲解概念和理论,重点放在代码的实现和示例上。 从零开始、全面系统、成体系的讲解数据结构和基本算法,循序渐进的讲述构建软件系统所常见的数据结构和算法。

研磨设计模式——跟着cc学设计系列视频教程
本视频课程是北京Java私塾原创精品书籍《研磨设计模式》一书的配套学习视频,由《研磨设计模式》的第一作者CC录制 课程目标:全面、系统的掌握GoF设计模式的知识,达到可以在实际项目开发中运用的能力 技术要点:如何实现可配置、如何实现缓存以及缓存的管理、如何实现用缓存来控制多实例的创建、如何实现参数化工厂、 如何实现可扩展工厂、如何实现原型管理器、如何实现Java的静态代理和动态代理、如何实现多线程处理队列请求、 如何实现命令的参数化配置、可撤销的操作、宏命令、队列请求和日志请求、如何实现翻页迭代、如何检测环状结构、 如何实现通用的增删改查、如何模拟工作流来处理流程、如何实现简单又通用的XML读取、如何实现模拟AOP的功能......

ssh+jbpm项目(某集团OA)视频教程
达到能综合使用Struts2+Spring3+Hibernate3+Jbpm4来进行实际项目开发的能力。 包括:ssh和jbpm的整合;数据字典;通用DAO(Spring+Hibernate+泛型+反射+SpEL+模板方法模式);自动生成UUID的加强版;分层开发、SSH联合的基本开发;翻页的taglib;示范真实值和表现值,数据参照的实现;文件上传下载;主子表操;登录验证码;登录控制的拦截器

Ajax+JSON基础实战视频教程
数据校验、Javascript模拟多线程、下拉列表联动、操作XML、AJAX结合JSON的操作、Json-lib的使用

深入浅出学Spring Web MVC视频教程
系统、完整的学习Spring Web MVC开发的知识。包括:Spring Web MVC入门;理解DispatcherServlet;注解式控制器开发详解;数据类型转换;数据格式化;数据验证; 拦截器;对Ajax的支持;文件上传下载;表单标签等内容;最后以一个综合的CRUD带翻页的应用示例来综合所学的知识

浏览(3977)|评论(0)   交流分类:Java|笔记分类: 深入剖析Spring……

评论(0)
请登录后评论 登录

关于我们 | 联系我们 | 用户协议 | 私塾在线服务协议 | 版权声明 | 隐私保护

版权所有 Copyright(C)2009-2012 私塾在线学习网