spingMVC模块handlerMapping的初始化过程
来源:互联网 发布:灯牌设计软件 编辑:程序博客网 时间:2024/04/29 08:28
spingMVC模块handlerMapping的初始化过程
一,请求的分发过程
首先简单描述一下,请求的分发过程。一个请求到来,会走到DispatcherServlet的doDispatch方法。这个方法非常重要,封装了整个请求的分发过程,其中有一段代码如下:
//根据请求找到对应的handler
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...... 调用拦截器等 ......
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
1,mappedHandler = getHandler(processedRequest, false)这个方法根据request得到的是一个HandlerExecutionChain对象,他包含了mvc模块的拦截器即handlerInterceptor和真正处理请求的handler。这个方法最终调用的是下面的这个方法,它也在ispatcherServlet中:
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;
}
二,DispatcherServlet中handlerMapping的初始化
- 在DispatcherServlet类下有这样一个方法
private void initHandlerMappings(ApplicationContext context) {根据方法的名字可以猜出,它就是初始化handermapping的地方。而这个方法的逻辑也不是很复杂,就是向容器索要HandlerMapping的实现类。可知这个时候handermapper的bean的定义已经在容器中了。但是,这段初始化的代码是怎么调起的呢?看下面的调用关系,原来是httpServletInit方法,它在servlet初始化的时候执行,负责context的建立以及相应的初始化工作。HandlerMapping的初始化要在context初始化之后(肯定要这样,不然还怎么向容器索要)。
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
OrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
onRefresh方法(不同于ApplicationContext的onRefresh),它在servlet初始化的时候执行,但是要在context初始化之后:
if (wac == null) {
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {// 这里才会出发HandlerMapping的初始化,而在这之间AppliContext已经建立
onRefresh(wac);}
目前为止,handlerMapping的初始化过程已经了然。但是或许还有些疑问,请求是怎样根据地址分发的呢,请求地址跟请求处理器是的对应关系是怎样建立的呢?
三,handleMapping在容器中的初始化过程
AnnotationDrivenBeanDefinitionParser的parse方法中的代码片段:
RootBeanDefinition methodMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
methodMappingDef.setSource(source);
methodMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodMappingDef.getPropertyValues().add("order", 0);
String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(methodMappingDef);
RequestMappingHandlerMapping的继承关系如下
其中红框中的AbstractHandlerMapping实现了HandlerMapping接口,而它的子类AbstractHandlerMethodMapping实现了容器的回调方法:afterPropertiesSet(),这就是HandlerMapping真正初始化的触发点(具体参见IOC实现源码):
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {上面的代码就是处理controller中的各个方法的逻辑。首先得到所有的handler,对应开发者写的controller;然后查找每个handler中映射请求的方法;最后初始化这些映射方法。接下来看看是怎么查找并处理这些映射方法的。
if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { if (isHandler(getApplicationContext().getType(beanName))){ detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods());}
protected void detectHandlerMethods(final Object handler) {Class<?> handlerType = (handler instanceof String) ?getApplicationContext().getType((String) handler) : handler.getClass();final Class<?> userType = ClassUtils.getUserClass(handlerType);Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {public boolean matches(Method method) {return getMappingForMethod(method, userType) != null;}});for (Method method : methods) {//对于每个方法,通过注解等信息解析出映射信息,然后进行注册T mapping = getMappingForMethod(method, userType);registerHandlerMethod(handler, method, mapping);}}
protected void registerHandlerMethod(Object handler, Method method, T mapping) { HandlerMethod handlerMethod; if (handler instanceof String) { String beanName = (String) handler; handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method); } else { handlerMethod = new HandlerMethod(handler, method); } HandlerMethod oldHandlerMethod = handlerMethods.get(mapping); if (oldHandlerMethod != null && !oldHandlerMethod.equals(handlerMethod)) { throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + handlerMethod.getBean() + "' bean method \n" + handlerMethod + "\nto " + mapping + ": There is already '" + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped."); } this.handlerMethods.put(mapping, handlerMethod); if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod); } Set<String> patterns = getMappingPathPatterns(mapping); for (String pattern : patterns) { if (!getPathMatcher().isPattern(pattern)) {//添加到urlMap中,查找时也会通过这个map查询
this.urlMap.add(pattern, mapping);} }}
回头再来看看dispatchServlet中调用的hm.getHanler方法,它也是在AbstractHandlerMapping中定义的。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 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); } return getHandlerExecutionChain(handler, request);}
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;}
this all。
0 0
- spingMVC模块handlerMapping的初始化过程
- spingMVC模块handlerMapping的初始化过程
- SpingMVC模块常用几种handlerMapping的初始化过程
- SpingMVC中的HandlerMapping
- SpingMVC中的HandlerMapping
- SpringMVC:dispatcherServlet对HandlerMapping的初始化
- SpringMVC 分析(一) handlerMapping 的初始化
- FreeSwitch 的初始化及其模块加载过程
- FreeSwitch 的初始化及其模块加载过程
- SpringAOP模块初始化过程
- http模块初始化过程
- SpingMVC中的三种HandlerMapping(映射器)
- QEMU在main函数前对模块的初始化过程
- SpingMvc的讲解
- spingmvc的请求流程
- spingMVC的原理
- ngx_core_module模块的初始化
- core模块的初始化
- 【单例深思】饿汉式与类加载
- 洛克菲勒家族信条
- eclipse中semantic.less文件编译报错解决办法
- 链式队列1.1
- 一个实现Android emulator root的简单脚本
- spingMVC模块handlerMapping的初始化过程
- Oracle(19)pl/sql编程 块(block)
- word2007 转 Pdf
- urllibtest
- View#post与Handler#post的区别,以及导致的内存泄漏分析
- 插件化:资源加载
- Redis集群安装
- vncserver使用
- 硬盘的寻址方式