- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
11.4.2 根据 request 信息寻找对应的 Handler
在 Spring 中最简单的映射处理器配置如下:
<bean id="simpleUrlMapping"
class="org.Springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/userlist.htm">userController</prop>
</props>
</property>
</bean>
在 Spring 加载的过程中,Spring 会将类型为 SimpleUrlHandlerMapping 的实例加载到 this.handlerMappings 中,按照常理推断,根据 request 提取对应的 Handler,无非就是提取当前实例中的 userController,但是 userController 为继承自 AbstractController 类型实例,与 Handler ExecutionChain 并无任何关联,那么这一步是如何封装的呢?
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache)
throws Exception {
return getHandler(request);
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with
name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
在之前的内容我们提过,在系统启动时 Spring 会将所有的映射类型的 bean 注册到 this.handlerMappings 变量中,所以此函数的目的就是遍历所有的 HandlerMapping,并调用其 getHandler 方法进行封装处理。以 SimpleUrlHandlerMapping 为例查看其 getHandler 方法如下:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
Exception {
//根据 request 获取对应的 handler
Object handler = getHandlerInternal(request);
if (handler == null) {
//如果没有对应 request 的 handler 则使用默认的 handler
handler = getDefaultHandler();
}
//如果也没有提供默认的 handler 则无法继续处理返回 null
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
return getHandlerExecutionChain(handler, request);
}
函数中首先会使用 getHandlerInternal 方法根据 request 信息获取对应的 Handler,如果以 SimpleUrlHandlerMapping 为例分析,那么我们推断此步骤提供的功能很可能就是根据 URL 找到匹配的 Controller 并返回,当然如果没有找到对应的 Controller 处理器那么程序会尝试去查找配置中的默认处理器,当然,当查找的 controller 为 String 类型时,那就意味着返回的是配置的 bean 名称,需要根据 bean 名称查找对应的 bean,最后,还要通过 getHandlerExecutionChain 方法对返回的 Handler 进行封装,以保证满足返回类型的匹配。下面详细分析这个过程。
1.根据 request 查找对应的 Handler
首先从根据 request 查找对应的 Handler 开始分析。
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
//截取用于匹配的 url 有效路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//根据路径寻找 Handler
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
if ("/".equals(lookupPath)) {
//如果请求的路径仅仅是”/”,那么使用 RootHandler 进行处理
rawHandler = getRootHandler();
}
if (rawHandler == null) {
//无法找到 handler 则使用默认 handler
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
//根据 beanName 获取对应的 bean
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
//模版方法
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
//直接匹配情况的处理
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// 通配符匹配的处理
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
}
String bestPatternMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " +
matchingPatterns);
}
bestPatternMatch = matchingPatterns.get(0);
}
if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern
(bestPatternMatch, urlPath);
// There might be multiple 'best patterns', let's make sure we have the correct
URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<String,
String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
uriTemplateVariables
.putAll(getPathMatcher().extractUriTemplateVariables
(matchingPattern, urlPath));
}
}
if (logger.isDebugEnabled()) {
logger.debug("URI Template variables for request [" + urlPath + "] are
" + uriTemplateVariables);
}
returnbuildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping,
uriTemplateVariables);
}
// No handler found...
return null;
}
根据 URL 获取对应 Handler 的匹配规则代码实现起来虽然很长,但是并不难理解,考虑了直接匹配与通配符两种情况。其中要提及的是 buildPathExposingHandler 函数,它将 Handler 封装成了 HandlerExecutionChain 类型。
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, Map<String, String> uriTemplateVariables) {
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern,
pathWithinMapping));
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor (uri
TemplateVariables));
}
return chain;
}
在函数中我们看到了通过将 Handler 以参数形式传入,并构建 HandlerExecutionChain 类型实例,加入了两个拦截器。此时我们似乎已经了解了 Spring 这样大番周折的目的。链处理机制,是 Spring 中非常常用的处理方式,是 AOP 中的重要组成部分,可以方便地对目标对象进行扩展及拦截,这是非常优秀的设计。
2.加入拦截器到执行链
getHandlerExecutionChain 函数最主要的目的是将配置中的对应拦截器加入到执行链中,以保证这些拦截器可以有效地作用于目标对象。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest
request) {
HandlerExecutionChain chain =
(handler instanceof HandlerExecutionChain) ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论