SpringMVC源码解读 - HandlerMapping - SimpleUrlHandlerMapping初始化
摘要:
SimpleUrlHandlerMapping只是参与Handler的注册,请求映射时由AbstractUrlHandlerMapping搞定.
初始化时,通过setMappings(Properties mappings)或者setUrlMap(Map<String, ?> urlMap)设置映射关系,然后通过WebApplicationObjectSupport的initApplicationContext调用registerHandlers进行注册.
覆写initApplicationContext方法时,先调用父类实现,然后才调用registerHandlers进行注册.其中最终的注册registerHandler实现是由AbstractUrlHandlerMapping实现的.
父类AbstractHandlerMapping继承了WebApplicationObjectSupport,所以SimpleUrlHandlerMapping可以通过覆写initApplicationContext注册Handler.
注册Handler前,不忘靠AbstractHandlerMapping来初始化拦截器.
// SimpleUrlHandlerMapping
1 /** 2 * Calls the {@link #registerHandlers} method in addition to the 3 * superclass's initialization. 4 */ 5 @Override 6 public void initApplicationContext() throws BeansException { 7 super.initApplicationContext(); 8 registerHandlers(this.urlMap); 9 }
initApplicationContext主要是进行拦截器的初始化.
extendInterceptors是留给子类用的扩展接口,暂时没有使用
detectMappedInterceptors是通过BeanFactoryUtils扫描应用下的全部MappedInterceptor类
initInterceptors初始化特定的拦截器,检查MappedInterceptor,在需要时适配adaptor HandlerInterceptor
// AbstractHandlerMapping
1 /** 2 * Initializes the interceptors. 3 * @see #extendInterceptors(java.util.List) 4 * @see #initInterceptors() 5 */ 6 @Override 7 protected void initApplicationContext() throws BeansException { 8 extendInterceptors(this.interceptors); 9 detectMappedInterceptors(this.mappedInterceptors); 10 initInterceptors(); 11 }
// AbstractHandlerMapping
1 /** 2 * Extension hook that subclasses can override to register additional interceptors, 3 * given the configured interceptors (see {@link #setInterceptors}). 4 * <p>Will be invoked before {@link #initInterceptors()} adapts the specified 5 * interceptors into {@link HandlerInterceptor} instances. 6 * <p>The default implementation is empty. 7 * @param interceptors the configured interceptor List (never {@code null}), 8 * allowing to add further interceptors before as well as after the existing 9 * interceptors 10 */ 11 protected void extendInterceptors(List<Object> interceptors) { 12 }
springmvc中经常使用BeanFactoryUtils扫描应用下的类来进行初始化.
// AbstractHandlerMapping
1 /** 2 * Detects beans of type {@link MappedInterceptor} and adds them to the list of mapped interceptors. 3 * This is done in addition to any {@link MappedInterceptor}s that may have been provided via 4 * {@link #setInterceptors(Object[])}. Subclasses can override this method to change that. 5 * 6 * @param mappedInterceptors an empty list to add MappedInterceptor types to 7 */ 8 protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) { 9 mappedInterceptors.addAll( 10 BeanFactoryUtils.beansOfTypeIncludingAncestors( 11 getApplicationContext(),MappedInterceptor.class, true, false).values()); 12 }
// AbstractHandlerMapping
1 /** 2 * Initialize the specified interceptors, checking for {@link MappedInterceptor}s and adapting 3 * HandlerInterceptors where necessary. 4 * @see #setInterceptors 5 * @see #adaptInterceptor 6 */ 7 protected void initInterceptors() { 8 if (!this.interceptors.isEmpty()) { 9 for (int i = 0; i < this.interceptors.size(); i++) { 10 Object interceptor = this.interceptors.get(i); 11 if (interceptor == null) { 12 throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null"); 13 } 14 if (interceptor instanceof MappedInterceptor) { 15 mappedInterceptors.add((MappedInterceptor) interceptor); 16 } 17 else { 18 adaptedInterceptors.add(adaptInterceptor(interceptor)); 19 } 20 } 21 } 22 }
适配HandlerInterceptor和WebRequestHandlerInterceptorAdapter(什么是WebRequestHandlerInterceptorAdapter,晚点再说吧,具体看到时候拦截器部分的分析)
// AbstractHandlerMapping
1 /** 2 * Adapt the given interceptor object to the HandlerInterceptor interface. 3 * <p>Supported interceptor types are HandlerInterceptor and WebRequestInterceptor. 4 * Each given WebRequestInterceptor will be wrapped in a WebRequestHandlerInterceptorAdapter. 5 * Can be overridden in subclasses. 6 * @param interceptor the specified interceptor object 7 * @return the interceptor wrapped as HandlerInterceptor 8 * @see org.springframework.web.servlet.HandlerInterceptor 9 * @see org.springframework.web.context.request.WebRequestInterceptor 10 * @see WebRequestHandlerInterceptorAdapter 11 */ 12 protected HandlerInterceptor adaptInterceptor(Object interceptor) { 13 if (interceptor instanceof HandlerInterceptor) { 14 return (HandlerInterceptor) interceptor; 15 } 16 else if (interceptor instanceof WebRequestInterceptor) { 17 return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor); 18 } 19 else { 20 throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName()); 21 } 22 }
这才到SimpleUrlHandlerMapping干活的地方,迭代urlMap调用AbstractUrlHandlerMapping的registerHandler进行注册
(保障url以"/"开头就不多说了)
// SimpleUrlHandlerMapping
1 /** 2 * Register all handlers specified in the URL map for the corresponding paths. 3 * @param urlMap Map with URL paths as keys and handler beans or bean names as values 4 * @throws BeansException if a handler couldn't be registered 5 * @throws IllegalStateException if there is a conflicting handler registered 6 */ 7 protected void registerHandlers(Map<String, Object> urlMap) throws BeansException { 8 if (urlMap.isEmpty()) { 9 logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping"); 10 } 11 else { 12 for (Map.Entry<String, Object> entry : urlMap.entrySet()) { 13 String url = entry.getKey(); 14 Object handler = entry.getValue(); 15 // Prepend with slash if not already present. 16 if (!url.startsWith("/")) { 17 url = "/" + url; 18 } 19 // Remove whitespace from handler bean name. 20 if (handler instanceof String) { 21 handler = ((String) handler).trim(); 22 } 23 registerHandler(url, handler); 24 } 25 } 26 }
// AbstractUrlHandlerMapping
1 /** 2 * Register the specified handler for the given URL path. 3 * @param urlPath the URL the bean should be mapped to 4 * @param handler the handler instance or handler bean name String 5 * (a bean name will automatically be resolved into the corresponding handler bean) 6 * @throws BeansException if the handler couldn't be registered 7 * @throws IllegalStateException if there is a conflicting handler registered 8 */ 9 protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { 10 Assert.notNull(urlPath, "URL path must not be null"); 11 Assert.notNull(handler, "Handler object must not be null"); 12 Object resolvedHandler = handler; 13 14 // Eagerly resolve handler if referencing singleton via name.不是单例同时不是懒加载 15 if (!this.lazyInitHandlers && handler instanceof String) { 16 String handlerName = (String) handler; 17 if (getApplicationContext().isSingleton(handlerName)) { 18 resolvedHandler = getApplicationContext().getBean(handlerName); 19 } 20 } 21 22 Object mappedHandler = this.handlerMap.get(urlPath);// 获取之前已经匹配的Handler 23 if (mappedHandler != null) { 24 if (mappedHandler != resolvedHandler) {// 如果新匹配得到的跟之前已解析到的handler不一致,则抛异常 25 throw new IllegalStateException( 26 "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath + 27 "]: There is already " + getHandlerDescription(mappedHandler) + " mapped."); 28 } 29 } 30 else { 31 if (urlPath.equals("/")) {// 设置rootHandler 32 if (logger.isInfoEnabled()) { 33 logger.info("Root mapping to " + getHandlerDescription(handler)); 34 } 35 setRootHandler(resolvedHandler); 36 } 37 else if (urlPath.equals("/*")) {// 设置默认的defaultHandler 38 if (logger.isInfoEnabled()) { 39 logger.info("Default mapping to " + getHandlerDescription(handler)); 40 } 41 setDefaultHandler(resolvedHandler); 42 } 43 else {// 最后才是普通handler的设置 44 this.handlerMap.put(urlPath, resolvedHandler); 45 if (logger.isInfoEnabled()) { 46 logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler)); 47 } 48 } 49 } 50 }