分析下springmvc的HandlerMapping映射的抽象类

初始化操作

通过initApplicationContext()方法进行初始化,其一般是由父类执行ApplicationContextAware#setApplicationContext()方法间接调用,源码奉上

	protected void initApplicationContext() throws BeansException {
//供子类扩展添加拦截器,目前spring没有自行实现
extendInterceptors(this.interceptors);
//搜寻springmvc中的MappedInterceptors保存至adaptedInterceptors集合
detectMappedInterceptors(this.adaptedInterceptors);
//将interceptors集合添加至adaptedInterceptors集合中
initInterceptors();
}

主要目的是获取springmvc上下文中的拦截器集合,此处特指MappedInterceptor

AbstractHandlerMapping#getHandler()-获取处理链对象

源码奉上

	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//getHandlerInternal(request)方法为抽象方法,供子类实现
//获取到的handler对象一般为bean/HandlerMethod
Object handler = getHandlerInternal(request);
//上述找不到则使用默认的处理类,没有设定则返回null,则会返回前台404错误
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//创建处理链对象
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//针对cros跨域请求的处理,此处就不分析了
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}

由以上代码分析可知,需要观察下如何获取handler对象以及创建HandlerExecutionChain处理链对象

AbstractHandlerMethodMapping#getHandlerInternal()-针对HandlerMethod的获取

主要是解析@Controller注解类中的@RequestMapping方法得到其中的HandlerMethod对象作为返回的Handler

	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取访问的路径,一般类似于request.getServletPath()返回不含contextPath的访问路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //获取读锁
this.mappingRegistry.acquireReadLock();
try {
//获取HandlerMethod作为handler对象,这里涉及到路径匹配的优先级
//优先级:精确匹配>最长路径匹配>扩展名匹配
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//HandlerMethod内部含有bean对象,其实指的是对应的Controller
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
//释放读锁
this.mappingRegistry.releaseReadLock();
}
}

AbstractUrlHandlerMapping#getHandlerInternal()-针对beanName的获取

源码奉上,此处的逻辑就较为简单了

	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//从handlerMap查找路径对应的beanName
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
} return handler;
}

AbstractHandlerMapping#getHandlerExecutionChain()-创建处理链对象

先附上HandlerExecutionChain的内部属性

        //真实处理请求对象
private final Object handler; //拦截器集合
private HandlerInterceptor[] interceptors; //拦截器集合
private List<HandlerInterceptor> interceptorList; //拦截器开始下标,默认正序执行
private int interceptorIndex = -1;

再奉上创建处理链对象的源码

	//此处的handler可为HandlerMethod/beanName
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}

处理链的创建基本就是 带有handler对象以及添加拦截器对象集合,用于后期的拦截

  • HandlerExecutionChain处理链内部含有handler对象,可为@RequestMapping对应的HandlerMethod对象,也可为springmvc上下文的beanName

  • HandlerExecutionChain处理链内部主要包含拦截器对象,其可从springmvc上下文获取HandlerInterceptor/MappedHandlerInterceptor类型作为内部集合;

    当然此处获得拦截器集合也是根据路径匹配获取的,比如mvc:interceptor指定的或者mvc:resource指定的

小结

SpringMVC源码情操陶冶-AbstractHandlerMapping的更多相关文章

  1. SpringMVC源码情操陶冶-DispatcherServlet简析(二)

    承接前文SpringMVC源码情操陶冶-DispatcherServlet类简析(一),主要讲述初始化的操作,本文将简单介绍springmvc如何处理请求 DispatcherServlet#doDi ...

  2. SpringMVC源码情操陶冶-AbstractHandlerMethodMapping

    承接前文SpringMVC源码情操陶冶-AbstractHandlerMapping,本文将介绍如何注册HandlerMethod对象作为handler 类结构瞧一瞧 public abstract ...

  3. SpringMVC源码情操陶冶-AbstractUrlHandlerMapping

    承接前文SpringMVC源码情操陶冶-AbstractHandlerMapping,前文主要讲解了如何获取handler处理对象,本文将针对beanName注册为handler对象作下解析 Abst ...

  4. SpringMVC源码情操陶冶-FreeMarker之web配置

    前言:本文不讲解FreeMarkerView视图的相关配置,其配置基本由FreeMarkerViewResolver实现,具体可参考>>>SpringMVC源码情操陶冶-ViewRe ...

  5. SpringMVC源码情操陶冶-DispatcherServlet

    本文对springmvc核心类DispatcherServlet作下简单的向导,方便博主与读者查阅 DispatcherServlet-继承关系 分析DispatcherServlet的继承关系以及主 ...

  6. SpringMVC源码情操陶冶-AnnotationDrivenBeanDefinitionParser注解解析器

    mvc:annotation-driven节点的解析器,是springmvc的核心解析器 官方注释 Open Declaration org.springframework.web.servlet.c ...

  7. SpringMVC源码情操陶冶-DispatcherServlet父类简析

    阅读源码有助于陶冶情操,本文对springmvc作个简单的向导 springmvc-web.xml配置 <servlet> <servlet-name>dispatch< ...

  8. SpringMVC源码情操陶冶-DispatcherServlet类简析(一)

    阅读源码有利于陶冶情操,此文承接前文SpringMVC源码情操陶冶-DispatcherServlet父类简析 注意:springmvc初始化其他内容,其对应的配置文件已被加载至beanFactory ...

  9. SpringMVC源码情操陶冶-HandlerAdapter适配器简析

    springmvc中对业务的具体处理是通过HandlerAdapter适配器操作的 HandlerAdapter接口方法 列表如下 /** * Given a handler instance, re ...

随机推荐

  1. Vijos P1113 不高兴的津津【模拟】

    不高兴的津津 描述 津津上初中了.妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班.另外每周妈妈还会送她去学习朗诵.舞蹈和钢琴.但是津津如果一天上课超过八个小时就会 ...

  2. Java大数应用

    1.大数加法 import java.math.BigInteger; import java.util.Scanner; public class Main { public static void ...

  3. 审计日志中的AOP

    审计跟踪(也称为审核日志)是一个安全相关的时间顺序记录,记录这些记录的目的是为已经影响在任何时候的详细操作,提供程序运行的证明文件记录.源或事件 MVC 自定义一个过滤器 public class A ...

  4. VUE之随笔小总结1

    VUE 它是一个构建用户界面的JavaScript框架vue指令: 是带有v-前缀的特殊属性,通过属性来操作元素 v-text:在元素当中插入文本 eg:属性值会覆盖自己插入的值 //插入一段文本&l ...

  5. Composer 是什么

    简单来说,Composer 是一个新的安装包管理工具,服务于 PHP 生态系统.它实际上包含了两个部分:Composer 和 Packagist.下面我们就简单说一下他们各自的用途. Composer ...

  6. Linux 中出现的-bash: syntax error near unexpected token `

    版权声明:本文为博主原创文章,未经博主允许不得转载. 在Linux 5中导入数据时,出现下面的错误. -bash: syntax error near unexpected token `(' 检查了 ...

  7. destoon框架二次开发【整理】

    =========================================================== destoon使用中的一些心得   ====================== ...

  8. Build path contains duplicate entry

    问题:Build path contains duplicate entry:''D:soft/Myeclipse 6.5/jre/lib/rt.jar' for project 'dataServi ...

  9. vue中组件之间的相互调用,及通用后台管理系统左侧菜单树的迭代生成

    由于本人近期开始学习使用vue搭建一个后端管理系统的前端项目,在左侧生成菜单树的时候遇到了一些问题.在这里记录下 分析:由于本人设定的菜单可以使多级结构,直接使用vue的v-for 遍历并不是很方便. ...

  10. python装饰器实现对异常代码出现进行监控

    异常,不应该存在,但是我们有时候会遇到这样的情况,比如我们监控服务器的时候,每一秒去采集一次信息,那么有一秒没有采集到我们想要的信息,但是下一秒采集到了, 而后每次的采集都能采集到,就那么一次采集不到 ...