摘要:

SimpleUrlHandlerMapping只是参与Handler的注册,请求映射时由AbstractUrlHandlerMapping搞定.

初始化时,通过setMappings(Properties mappings)或者setUrlMap(Map<String, ?> urlMap)设置映射关系,然后通过WebApplicationObjectSupport的initApplicationContext调用registerHandlers进行注册.

覆写initApplicationContext方法时,先调用父类实现,然后才调用registerHandlers进行注册.其中最终的注册registerHandler实现是由AbstractUrlHandlerMapping实现的.

父类AbstractHandlerMapping继承了WebApplicationObjectSupport,所以SimpleUrlHandlerMapping可以通过覆写initApplicationContext注册Handler.

注册Handler前,不忘靠AbstractHandlerMapping来初始化拦截器.

// SimpleUrlHandlerMapping

     /**
* Calls the {@link #registerHandlers} method in addition to the
* superclass's initialization.
*/
@Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}

initApplicationContext主要是进行拦截器的初始化.

  extendInterceptors是留给子类用的扩展接口,暂时没有使用

  detectMappedInterceptors是通过BeanFactoryUtils扫描应用下的全部MappedInterceptor类

  initInterceptors初始化特定的拦截器,检查MappedInterceptor,在需要时适配adaptor HandlerInterceptor

// AbstractHandlerMapping

     /**
* Initializes the interceptors.
* @see #extendInterceptors(java.util.List)
* @see #initInterceptors()
*/
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.mappedInterceptors);
initInterceptors();
}

// AbstractHandlerMapping

     /**
* Extension hook that subclasses can override to register additional interceptors,
* given the configured interceptors (see {@link #setInterceptors}).
* <p>Will be invoked before {@link #initInterceptors()} adapts the specified
* interceptors into {@link HandlerInterceptor} instances.
* <p>The default implementation is empty.
* @param interceptors the configured interceptor List (never {@code null}),
* allowing to add further interceptors before as well as after the existing
* interceptors
*/
protected void extendInterceptors(List<Object> interceptors) {
}

springmvc中经常使用BeanFactoryUtils扫描应用下的类来进行初始化.

// AbstractHandlerMapping

     /**
* Detects beans of type {@link MappedInterceptor} and adds them to the list of mapped interceptors.
* This is done in addition to any {@link MappedInterceptor}s that may have been provided via
* {@link #setInterceptors(Object[])}. Subclasses can override this method to change that.
*
* @param mappedInterceptors an empty list to add MappedInterceptor types to
*/
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(),MappedInterceptor.class, true, false).values());
}

// AbstractHandlerMapping

     /**
* Initialize the specified interceptors, checking for {@link MappedInterceptor}s and adapting
* HandlerInterceptors where necessary.
* @see #setInterceptors
* @see #adaptInterceptor
*/
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
if (interceptor instanceof MappedInterceptor) {
mappedInterceptors.add((MappedInterceptor) interceptor);
}
else {
adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
}

适配HandlerInterceptor和WebRequestHandlerInterceptorAdapter(什么是WebRequestHandlerInterceptorAdapter,晚点再说吧,具体看到时候拦截器部分的分析)

// AbstractHandlerMapping

     /**
* Adapt the given interceptor object to the HandlerInterceptor interface.
* <p>Supported interceptor types are HandlerInterceptor and WebRequestInterceptor.
* Each given WebRequestInterceptor will be wrapped in a WebRequestHandlerInterceptorAdapter.
* Can be overridden in subclasses.
* @param interceptor the specified interceptor object
* @return the interceptor wrapped as HandlerInterceptor
* @see org.springframework.web.servlet.HandlerInterceptor
* @see org.springframework.web.context.request.WebRequestInterceptor
* @see WebRequestHandlerInterceptorAdapter
*/
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
}
else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
}
else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}

这才到SimpleUrlHandlerMapping干活的地方,迭代urlMap调用AbstractUrlHandlerMapping的registerHandler进行注册

(保障url以"/"开头就不多说了)

// SimpleUrlHandlerMapping

     /**
* Register all handlers specified in the URL map for the corresponding paths.
* @param urlMap Map with URL paths as keys and handler beans or bean names as values
* @throws BeansException if a handler couldn't be registered
* @throws IllegalStateException if there is a conflicting handler registered
*/
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
}
}
}

// AbstractUrlHandlerMapping

 /**
* Register the specified handler for the given URL path.
* @param urlPath the URL the bean should be mapped to
* @param handler the handler instance or handler bean name String
* (a bean name will automatically be resolved into the corresponding handler bean)
* @throws BeansException if the handler couldn't be registered
* @throws IllegalStateException if there is a conflicting handler registered
*/
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler; // Eagerly resolve handler if referencing singleton via name.不是单例同时不是懒加载
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
if (getApplicationContext().isSingleton(handlerName)) {
resolvedHandler = getApplicationContext().getBean(handlerName);
}
} Object mappedHandler = this.handlerMap.get(urlPath);// 获取之前已经匹配的Handler
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {// 如果新匹配得到的跟之前已解析到的handler不一致,则抛异常
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {// 设置rootHandler
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {// 设置默认的defaultHandler
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {// 最后才是普通handler的设置
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}

SpringMVC源码解读 - HandlerMapping - SimpleUrlHandlerMapping初始化的更多相关文章

  1. SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化

    RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping来定义controller. @Controller @RequestMapp ...

  2. SpringMVC源码解读 - HandlerMapping

    SpringMVC在请求到handler处理器的分发这步是通过HandlerMapping模块解决的.handlerMapping 还处理拦截器. 先看看HandlerMapping的继承树吧 可以大 ...

  3. SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化

    AbstractDetectingUrlHandlerMapping是通过扫描方式注册Handler,收到请求时由AbstractUrlHandlerMapping的getHandlerInterna ...

  4. SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping请求分发

    AbstractHandlerMethodMapping实现接口getHandlerInternal,定义查找流程 RequestMappingInfoHandlerMapping根据RequestM ...

  5. SpringMVC源码解读 - HandlerMapping - AbstractUrlHandlerMapping系列request分发

    AbstractHandlerMapping实现HandlerMapping接口定的getHandler 1. 提供getHandlerInternal模板方法给子类实现 2. 如果没有获取Handl ...

  6. SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系

    一般我们开发时,使用最多的还是@RequestMapping注解方式. @RequestMapping(value = "/", param = "role=guest& ...

  7. SpringMVC源码解读 - RequestMapping注解实现解读

    SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系  https://www.cnblogs.com/leftthen/p/520840 ...

  8. SpringMVC源码解读 - RequestMapping注解实现解读 - RequestMappingInfo

    使用@RequestMapping注解时,配置的信息最后都设置到了RequestMappingInfo中. RequestMappingInfo封装了PatternsRequestCondition, ...

  9. springMVC源码分析--HandlerMapping(一)

    HandlerMapping的工作就是为每个请求找到合适的请求找到一个处理器handler,其实现机制简单来说就是维持了一个url到Controller关系的Map结构,其提供的实际功能也是根据req ...

随机推荐

  1. Codeforces-591C题解

    一.题目链接 http://codeforces.com/problemset/problem/591/C 二.题意 给定一个只含数字0和1的数组,通过如下方式,变成不再变化的01组合,最少需要操作几 ...

  2. poj 3790 Recursively Palindromic Partitions

    /*摘抄自博客:Recursively Palindromic Partitions Time Limit: 1000MS Memory Limit: 65536K Total Submissions ...

  3. 巧用setTimeout函数设置程序后门

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. centos 安装php7

    yum安装php7 删除之前的版本 # yum remove php* rpm 安装 Php7 相应的 yum源 CentOS/RHEL 7.x: # rpm -Uvh https://dl.fedo ...

  5. C# 一维码生成

    概念 一维条码即指条码条和空的排列规则,常用的一维码的码制包括:EAN码.39码.交叉25码.UPC码.128码.93码,ISBN码,及Codabar(库德巴码)等. 条形码起源于 20 世纪 40 ...

  6. SDN openflow 学习小得

    一.openflow 大概的工作原理 SDN 的一个大概简陋图, 同网段通讯 1.我们传统网络 pc1 10.1.1.1 要找同一子网的 pc2 10.1.1.2  通过广播洪泛.找到pc2,然后转发 ...

  7. Weak References

    http://docwiki.embarcadero.com/RADStudio/Seattle/en/Automatic_Reference_Counting_in_Delphi_Mobile_Co ...

  8. Sass 入门 (一) 安装Sass

    Sass安装 ruby安装 因为sass依赖于ruby环境,所以装sass之前先确认装了ruby.先导官网下载个ruby 在安装的时候,请勾选Add Ruby executables to your ...

  9. npm 全局环境变量配置

      我们要先配置npm的全局模块的存放路径以及cache的路径,例如我希望将以上两个文件夹放在NodeJS的主目录下,便在NodeJs下建立”node_global”及”node_cache”两个文件 ...

  10. bootstrap 的页码显示问题-------------德州

    之前一个小bug,无论上边怎么搜索,下边的页码,不会改变 调整: 1,在mapper中添加计数, 2,找到service,queryPage中添加, 3,关键一部,如果没有会报错:,找不到该列 so, ...