SpringMVC源码情操陶冶-AbstractHandlerMapping
分析下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上下文的beanNameHandlerExecutionChain处理链内部主要包含拦截器对象,其可从springmvc上下文获取
HandlerInterceptor
/MappedHandlerInterceptor
类型作为内部集合;
当然此处获得拦截器集合也是根据路径匹配获取的,比如mvc:interceptor
指定的或者mvc:resource
指定的
小结
SpringMVC源码情操陶冶-AbstractHandlerMapping的更多相关文章
- SpringMVC源码情操陶冶-DispatcherServlet简析(二)
承接前文SpringMVC源码情操陶冶-DispatcherServlet类简析(一),主要讲述初始化的操作,本文将简单介绍springmvc如何处理请求 DispatcherServlet#doDi ...
- SpringMVC源码情操陶冶-AbstractHandlerMethodMapping
承接前文SpringMVC源码情操陶冶-AbstractHandlerMapping,本文将介绍如何注册HandlerMethod对象作为handler 类结构瞧一瞧 public abstract ...
- SpringMVC源码情操陶冶-AbstractUrlHandlerMapping
承接前文SpringMVC源码情操陶冶-AbstractHandlerMapping,前文主要讲解了如何获取handler处理对象,本文将针对beanName注册为handler对象作下解析 Abst ...
- SpringMVC源码情操陶冶-FreeMarker之web配置
前言:本文不讲解FreeMarkerView视图的相关配置,其配置基本由FreeMarkerViewResolver实现,具体可参考>>>SpringMVC源码情操陶冶-ViewRe ...
- SpringMVC源码情操陶冶-DispatcherServlet
本文对springmvc核心类DispatcherServlet作下简单的向导,方便博主与读者查阅 DispatcherServlet-继承关系 分析DispatcherServlet的继承关系以及主 ...
- SpringMVC源码情操陶冶-AnnotationDrivenBeanDefinitionParser注解解析器
mvc:annotation-driven节点的解析器,是springmvc的核心解析器 官方注释 Open Declaration org.springframework.web.servlet.c ...
- SpringMVC源码情操陶冶-DispatcherServlet父类简析
阅读源码有助于陶冶情操,本文对springmvc作个简单的向导 springmvc-web.xml配置 <servlet> <servlet-name>dispatch< ...
- SpringMVC源码情操陶冶-DispatcherServlet类简析(一)
阅读源码有利于陶冶情操,此文承接前文SpringMVC源码情操陶冶-DispatcherServlet父类简析 注意:springmvc初始化其他内容,其对应的配置文件已被加载至beanFactory ...
- SpringMVC源码情操陶冶-HandlerAdapter适配器简析
springmvc中对业务的具体处理是通过HandlerAdapter适配器操作的 HandlerAdapter接口方法 列表如下 /** * Given a handler instance, re ...
随机推荐
- STL中的nth_element()方法的使用
STL中的nth_element()方法的使用 通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比 ...
- 常用Windows DOS命令项目部署经常用到
img { max-width: 100% } 前两天部署.netcore项目,首先是生产环境域名访问不了,再到.netcore项目IIS部署502.5,在到莫名其妙的500,在排查项目部署问题的时候 ...
- 利用脚本将EXCEl表倒入PowerDesigner中
1.Excel表格样式 2.脚本代码 '****************************************************************************** O ...
- 使用nginx处理静态资源请求,其余交给node
由于项目后台使用的是node,然而node不适合对静态资源的处理,因为他的异步处理(事件轮询)机制,所以更擅长的是密集I/O型的应用,所以我就有了一个想法,使用nginx来做反向代理,当请求的是静态资 ...
- Python数据类型一:数字与运算符
数字 一.数值类型 python中支持的数值类型有以下几种: 1.整型(Int) - 通常被称为是整型或整数,是正或负整数,不带小数点.Python3 整型是没有限制大小的,可以当作 Long 类型使 ...
- 无序列表li横向排列的间隙问题
今天在写页面的时候,无意中遇到这样一个问题,就是无序列表li横向排列即做成导航栏时,列表项间有间隙. 如: 将列表项li变成列表块后(即将li标签设置为,display:inline-block后), ...
- reduceByKeyLocally
2017年3月15日, 星期三 reduceByKeyLocally--Transformation类算子 代码示例
- css3中的关键帧技术分析应用
最近在研究网页加载进度效果的时候发现可以使用css3实现这个效果. 使用css3实现完全不需要图片,相比使用loading.gif的实现来说可能更快. 使用css3实现动态加载的效果,主要会涉及到几个 ...
- css background之设置图片为背景技巧
css background之设置图片为背景技巧-css 背景 Background是什么意思,翻译过来有背景意思.同样在css里面作为css属性一成员同样是有背景意思,并且是设置背景图片.背景颜色. ...
- 关于在vue-cli中使用微信自动登录和分享
(以下所有接口由后台提供) 一.微信自动登录 //定义事件 methods:{ //判断是否微信登陆 是不是微信浏览器 isWeiXin() { let ua = window.navigator.u ...