Spring MVC源码解析:HandlerMapping处理器映射器详解
创作时间:
作者:
@小白创作中心
Spring MVC源码解析:HandlerMapping处理器映射器详解
引用
CSDN
1.
https://blog.csdn.net/Lxn2zh/article/details/128545470
本文将深入分析Spring MVC框架中的HandlerMapping处理器映射器的源码实现。从概念到具体实现,逐步展开,帮助读者理解Spring MVC的请求处理流程。
系列文章目录
- springmvc源码之Web上下文初始化
- springmvc源码之DispatcherServlet前端控制器
- springmvc源码之HandlerMapping处理器映射器
HandlerMapping处理器映射器
HandlerMapping的主要作用是根据请求(request)找到相应的处理器(Handler)和拦截器(Interceptors)。其核心方法如下:
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
实现类
HandlerMapping帮助DispatcherServlet进行web请求的url到具体处理类的匹配,用来根据请求的url查找Handler,内部维护的Map<String, Object>映射,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
Spring自带了多个处理器映射实现:
- BeanNameUrlHandlerMapping:根据控制器Bean的名字将控制器映射到URL
- ControllerBeanNameHandlerMapping:与BeanNameUrlHandlerMapping类似
- ControllerClassNameHandlerMapping:通过使用控制器的类名作为URL基础将控制器映射到URL
- DefaultAnnotationHandlerMapping:将请求映射给使用@RequestMapping注解的控制器和控制器方法
- SimpleUrlHandlerMapping:使用定义在Spring应用上下文的集合将控制器映射到URL
- RequestMappingHandlerMapping:SpringMVC3.1新增的,在springMVC3.1之前,DefaultAnnotationHandlerMapping会在类级别上选中一个控制器,然后通过AnnotationMethodHandlerAdapter定位到具体要调用的方法;而在SpringMVC3.1之后,这些操作全都放生在RequestMappingHandlerMapping中,从类级别和方法级别的@RequestMapping注解中获取到路径映射信息,使得在HandlerInterceptor中获取到的处理器肯定是一个HandlerMethod类型
配置
<!-- 开启注解 -->
<mvc:annotation-driven/>
<bean id="defaultAnnotationHandlerMapping"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<mvc:annotation-driven/>配置的作用:
- 自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdater、ExceptionHandlerExceptionResolver三个bean
- 支持使用ConversionService实例对表单参数进行类型转换
- 支持使用@NumberFormatannotation、@DataTimeFormat注解完成数据类型的格式化
- 支持使用@Vaild注解对JavaBean实例进行JSR 303验证
- 支持使用@RequestBody和@ResponseBody注解
RequestMappingHandlerMapping源码
由于一般都使用<mvc:annotation-driven/>进行配置,所以就以RequestMappingHandlerMapping为例进行讲解
创建
首先进行创建
其实现了ApplicationContextAware,所以需要执行setApplicationContext
// 调用链路 org.springframework.context.support.ApplicationObjectSupport#setApplicationContext ——>org.springframework.context.support.ApplicationObjectSupport#initApplicationContext(org.springframework.context.ApplicationContext) -->org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext
// org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext
protected void initApplicationContext() throws BeansException {
// 扩展interceptors的方法,空实现
extendInterceptors(this.interceptors);
// 将容器中的所有MappedInterceptor类型的bean添加到mappedInterceptors中
detectMappedInterceptors(this.adaptedInterceptors);
// 初始化Interceptor,将interceptors中的对象添加到adaptedInterceptors中
initInterceptors();
}
其实现了InitializingBean,需要执行afterPropertiesSet
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet
public void afterPropertiesSet() {
initHandlerMethods();
}
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods
protected void initHandlerMethods() {
// 拿到容器中的bean,筛选出Handler
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
}
// (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); 判断
if (beanType != null && isHandler(beanType)) {
// 将访问地址、Method进行映射
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
访问
在进行访问的时候会通过org.springframework.web.servlet.DispatcherServlet#getHandler方法来遍历handlerMappings
HandlerExecutionChain handler = hm.getHandler(request);
来调用HandlerMapping的getHandler方法
// org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 找到Handler,根据地址找到对应的方法
Object handler = getHandlerInternal(request);
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);
}
// 为handler生成执行链,即添加interceptor
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
getHandlerInternal
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
getHandlerExecutionChain
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;
}
参考文献
- HandlerMapping
热门推荐
正惩罚在家庭教育中的应用
研究证实:Nd:YAG激光治疗牙齿敏感安全有效
天冬入选药食同源名单,从养生食材到餐桌新宠
榆林十大必打卡旅游景点!榆林旅游推荐榜!小小榆林,大大惊喜
2024辽沈地区医疗健康行业大事件回顾!快看谁家上榜了
哈佛大学专业设置全解析:从社会科学到自然科学,四大领域专业详解
花游双人项目首夺奥运金牌,王柳懿/王芊懿创造历史
治疗脑梗塞最新药物有哪些
周末DIY沙拉油条虾滑,朋友圈里的美食达人就是你!
多巴胺与情绪调节:从运动到饮食的科学方法,最新研究发现或可治疗阿尔茨海默症
六神丸:中药里的“抗生素”,六种成分科学解读
用“窗帘”当卫生巾?卫生巾使用不当,当心妇科炎症缠上你
中高考来了,如何用正面话语缓解考前焦虑?
刘禹锡《酬乐天扬州初逢席上见赠》:从凄凉到豁达的人生感悟
蝴蝶兰选购与养护指南:环境要求与病虫害防治全解析
云南旅游防坑指南:买错东西?被强制购物?不要怕,咱上面有人!
普洱茶饼包装材料选择:哪些适合装普洱茶饼以保护其品质与风味?
成就鲁迅从文艺青年到大先生,身后是“相知之深有如兄弟”的友人
儿童健康保障:五大领域全面守护成长
私人房屋买卖合同的法律效力及注意事项
新研究揭示竹笋作为世界未来食品的潜力
王维三首五绝里的生活哲学:给现代人的精神良方
广州深圳社保缴费档次大对比:医保待遇谁更强?
按摩床选购指南:5种材质优劣对比与功能选择要点
虚幻引擎等四大案例展现C++框架开发实力
从“胡一菲”到汉服推广大使:娄艺潇的转型之路
外贸人必读:WhatsApp和Skype助力业务拓展
池谷敏郎推荐:50种抗炎食物助你加速自愈
狗狗睡眠时间的秘密,你知道多少?
39健康网:吃药后喝醋不影响药效,还能保护药物