spring 源码 阅读 笔记 之 HandlerMapping

类图:


AbstractHandlerMapping.java : 支持Handler排序、默认的Handler以及Handler拦截器。
1. Handler排序:继承Ordered接口,每一个HanderMapping都有一个优先值(int order),默认的优先值为最大的优先值。
2. 拦截器:支持两种类型的拦截器(HandlerInterceptor和WebRequestInterceptor:二者的区别在于HandlerInterceptor处理的对象是标准的servlet请求和响应,而WebRequestInterceptor处理的对象是spring的WebRequest),所有的拦截器存放在:private HandlerInterceptor[] adaptedInterceptors;中。对于WebRequestInterceptor类型拦截器,通过WebRequestHandlerInterceptorAdapter适配器加入到数组中。
3. 本类getHandler()方法返回的是包含一系列Interceptor的HandlerExecutionChain,不是raw Handler。HandlerExecutionChain包装了raw Handler以及一系列Interceptor。
4. 本类继承WebApplicationObjectSupport是为了通过Bean name取得从spring上下文中取实际的bean(Object handler = getApplicationContext().getBean(handlerName))

AbstractUrlHandlerMapping.java:包含映射Handler到URLS的基础功能。支持直接映射("/test" "/test")和Ant-style映射("/t*""/test" 和 "/team"),对于每个请求会找到其最佳映射(最长匹配)。
1. private Object rootHandler:对应URL为”/”或null
2. private boolean lazyInitHandlers = false:对于单例类型的Handler,可以通过设置其lazy-init和此属性为true(缺一不可),实现lazily initialization。这是因为即使该bean的lazy-init属性设为true,但是在注册Handler时如果lazyInitHandlers为true,也会对该bean进行初始化:
       // 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);
}
}
3. Ant-style匹配:

                //urlPath对应为request中的请求路径
                //handlerMap中保存了所有注册的匹配路径
String bestPathMatch = null;
for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {
String registeredPath = (String) it.next();
if (getPathMatcher().match(registeredPath, urlPath) &&
(bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) {
                                //遍历寻找到最长的匹配路径
bestPathMatch = registeredPath;
}
}
4. PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE:本方法会在raw Handler中增加一个拦截器:
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(pathWithinMapping));
该拦截器是本方法的一个内部类:功能是在Handler执行前request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
pathWithinMapping的生成策略示例(三个参数依次对就为:注册的url匹配模式、请求的url路径、pathWithinMapping):
• '/docs/cvs/commit.html' and '/docs/cvs/commit.html -> ''
• '/docs/*' and '/docs/cvs/commit -> 'cvs/commit'
• '/docs/cvs/*.html' and '/docs/cvs/commit.html -> 'commit.html'
• '/docs/**' and '/docs/cvs/commit -> 'cvs/commit'
• '/docs/**\/*.html' and '/docs/cvs/commit.html -> 'cvs/commit.html'
• '/*.html' and '/docs/cvs/commit.html -> 'docs/cvs/commit.html'
• '*.html' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
• '*' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
5. 内部类的使用:本方法中有一个私有内部类:该类的使用条件:只在本方法中使用。
同时该内部类与其包含类之间存在调用关系。
  private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter {
private final String pathWithinMapping;
public PathExposingHandlerInterceptor(String pathWithinMapping) {
this.pathWithinMapping = pathWithinMapping;
}
public boolean preHandle(HttpServletRequest request,       HttpServletResponse response, Object handler) {
                        //调用其包含类中的方法
exposePathWithinMapping(this.pathWithinMapping, request);
return true;
}
}

AbstractDetectingUrlHandlerMapping.java:在上下文中寻找所有存在URL映射属性的Handler bean:
        1. private boolean detectHandlersInAncestorContexts = false:是否需要在其父应用上下文件中寻找Handler bean。
List urls = new ArrayList();
if (beanName.startsWith("/")) {
                        //bean的名称以”/”开始才会认为其映射到一个URL
urls.add(beanName);
}
String[] aliases = getApplicationContext().getAliases(beanName);
for (int i = 0; i < aliases.length; i++) {
if (aliases[i].startsWith("/")) {
                               //bean的别名以”/”开始才会认为其映射到一个URL
urls.add(aliases[i]);
}
}
                if (!ObjectUtils.isEmpty(urls)) {
      // 只有当urls不为空时,我们才会认为这是一个Handler
      registerHandler(urls, beanName);
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值