SpringMVC源碼解讀之 HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化。本站提示廣大學習愛好者:(SpringMVC源碼解讀之 HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化)文章只能為提供參考,不一定能成為您想要的結果。以下是SpringMVC源碼解讀之 HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化正文
AbstractDetectingUrlHandlerMapping是經由過程掃描方法注冊Handler,收到要求時由AbstractUrlHandlerMapping的getHandlerInternal停止分發.
共有5個子類,一個籠統類.
與SimpleUrlHandlerMapping相似,經由過程覆寫initApplicationContext,然後挪用detectHandlers停止初始化.
detectHandlers經由過程BeanFactoryUtils掃描運用下的Object,然後預留determineUrlsForHandler給子類依據Handler生成對應的url.
注冊應用的registerHandler仍然由AbstractUrlHandlerMapping供給.
// AbstractDetectingUrlHandlerMapping /** * Calls the {@link #detectHandlers()} method in addition to the * superclass's initialization. */ @Override public void initApplicationContext() throws ApplicationContextException { super.initApplicationContext(); detectHandlers(); }
這邊一樣是挪用AbstractHandlerMapping的initApplicationContext初始化攔阻器.
配角上場,detectHandlers,掃描Handlers
// AbstractDetectingUrlHandlerMapping /** * Register all handlers found in the current ApplicationContext. * <p>The actual URL determination for a handler is up to the concrete * {@link #determineUrlsForHandler(String)} implementation. A bean for * which no such URLs could be determined is simply not considered a handler. * @throws org.springframework.beans.BeansException if the handler couldn't be registered * @see #determineUrlsForHandler(String) */ protected void detectHandlers() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Looking for URL mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); // Take any bean name that we can determine URLs for. for (String beanName : beanNames) { String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { // URL paths found: Let's consider it a handler. registerHandler(urls, beanName); } else { if (logger.isDebugEnabled()) { logger.debug("Rejected bean name '" + beanName + "': no URL paths identified"); } } } }
這邊預留的模板辦法界說以下:
/** * Determine the URLs for the given handler bean. * @param beanName the name of the candidate bean * @return the URLs determined for the bean, * or {@code null} or an empty array if none */ protected abstract String[] determineUrlsForHandler(String beanName); 我們再來看看模板辦法在BeanNameUrlHandlerMapping和AbstractControllerUrlHandlerMapping中的完成吧. BeanNameUrlHandlerMapping異常簡略,就完成了determineUrlsForHandler. 個中的alias應當是應當就是經由過程beanName在設置裝備擺設文件中設置裝備擺設的. // BeanNameUrlHandlerMapping /** * Checks name and aliases of the given bean for URLs, starting with "/". */ @Override protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList<String>(); if (beanName.startsWith("/")) { urls.add(beanName); } String[] aliases = getApplicationContext().getAliases(beanName); for (String alias : aliases) { if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); }
再來看看AbstractControllerUrlHandlerMapping中的完成
isEligibleForMapping斷定controller能否被消除在外(經由過程包package消除或類class消除).
buildUrlsForHandler由子類完成詳細的url生陳規則
isControllerType斷定能否Controller的子類
buildUrlsForHandler預留給子類臨盆url的模板辦法.
// AbstractControllerUrlHandlerMapping /** * This implementation delegates to {@link #buildUrlsForHandler}, * provided that {@link #isEligibleForMapping} returns {@code true}. */ @Override protected String[] determineUrlsForHandler(String beanName) { Class beanClass = getApplicationContext().getType(beanName); if (isEligibleForMapping(beanName, beanClass)) { return buildUrlsForHandler(beanName, beanClass); } else { return null; } } // AbstractControllerUrlHandlerMapping /**斷定controller能否被消除在外(經由過程包package消除或類class消除). * Determine whether the specified controller is excluded from this mapping. * @param beanName the name of the controller bean * @param beanClass the concrete class of the controller bean * @return whether the specified class is excluded * @see #setExcludedPackages * @see #setExcludedClasses */ protected boolean isEligibleForMapping(String beanName, Class beanClass) { if (beanClass == null) { if (logger.isDebugEnabled()) { logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " + "because its bean type could not be determined"); } return false; } if (this.excludedClasses.contains(beanClass)) { if (logger.isDebugEnabled()) { logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " + "because its bean class is explicitly excluded: " + beanClass.getName()); } return false; } String beanClassName = beanClass.getName(); for (String packageName : this.excludedPackages) { if (beanClassName.startsWith(packageName)) { if (logger.isDebugEnabled()) { logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " + "because its bean class is defined in an excluded package: " + beanClass.getName()); } return false; } } return isControllerType(beanClass); } // AbstractControllerUrlHandlerMapping /** * Determine whether the given bean class indicates a controller type * that is supported by this mapping strategy. * @param beanClass the class to introspect */ protected boolean isControllerType(Class beanClass) { return this.predicate.isControllerType(beanClass); } // ControllerTypePredicate 這邊供給2個api,分離斷定是Controller的子類照樣MultiActionController的子類. /** * Internal helper class that identifies controller types. * * @author Juergen Hoeller * @since .. */ class ControllerTypePredicate { public boolean isControllerType(Class beanClass) { return Controller.class.isAssignableFrom(beanClass); } public boolean isMultiActionControllerType(Class beanClass) { return MultiActionController.class.isAssignableFrom(beanClass); } }
預留生成url的模板辦法
// AbstractControllerUrlHandlerMapping /** * Abstract template method to be implemented by subclasses. * @param beanName the name of the bean * @param beanClass the type of the bean * @return the URLs determined for the bean */ protected abstract String[] buildUrlsForHandler(String beanName, Class beanClass);
再來看看AbstractControllerUrlHandlerMapping的2個完成ControllerBeanNameUrlHandlerMapping和ControllerClassNameUrlHandlerMapping.
其實這兩個,很簡略,一個是依據beanName來臨盆url,一個是依據className來臨盆url.
// ControllerBeanNameUrlHandlerMapping @Override protected String[] buildUrlsForHandler(String beanName, Class beanClass) { List<String> urls = new ArrayList<String>(); urls.add(generatePathMapping(beanName)); String[] aliases = getApplicationContext().getAliases(beanName);// 也獲得設置裝備擺設的別號 for (String alias : aliases) { urls.add(generatePathMapping(alias)); } return StringUtils.toStringArray(urls); } // ControllerBeanNameUrlHandlerMapping /**對path添加前後綴,還有/ * Prepends a '/' if required and appends the URL suffix to the name. */ protected String generatePathMapping(String beanName) { String name = (beanName.startsWith("/") ? beanName : "/" + beanName); StringBuilder path = new StringBuilder(); if (!name.startsWith(this.urlPrefix)) { path.append(this.urlPrefix); } path.append(name); if (!name.endsWith(this.urlSuffix)) { path.append(this.urlSuffix); } return path.toString(); } // ControllerClassNameUrlHandlerMapping
直接拜托給generatePathMappings完成
@Override protected String[] buildUrlsForHandler(String beanName, Class beanClass) { return generatePathMappings(beanClass); } // ControllerClassNameUrlHandlerMapping
經由過程buildPathPrefix獲得path的前綴
經由過程ClassUtils獲得className,如BookController(不帶包名),同時應用cglib署理的成績一並處理
依據年夜小寫能否敏感,轉換className(默許caseSensitive = false;)
isMultiActionControllerType斷定Controller能否MultiActionController的子類,就是controller能否包括多個handler
/** * Generate the actual URL paths for the given controller class. * <p>Subclasses may choose to customize the paths that are generated * by overriding this method. * @param beanClass the controller bean class to generate a mapping for * @return the URL path mappings for the given controller */ protected String[] generatePathMappings(Class beanClass) { StringBuilder pathMapping = buildPathPrefix(beanClass); String className = ClassUtils.getShortName(beanClass); String path = (className.endsWith(CONTROLLER_SUFFIX) ? className.substring(, className.lastIndexOf(CONTROLLER_SUFFIX)) : className); if (path.length() > ) { if (this.caseSensitive) { pathMapping.append(path.substring(, ).toLowerCase()).append(path.substring()); } else { pathMapping.append(path.toLowerCase()); } } if (isMultiActionControllerType(beanClass)) { return new String[] {pathMapping.toString(), pathMapping.toString() + "/*"}; } else { return new String[] {pathMapping.toString() + "*"}; } } // ControllerClassNameUrlHandlerMapping /** * Build a path prefix for the given controller bean class. * @param beanClass the controller bean class to generate a mapping for * @return the path prefix, potentially including subpackage names as path elements */ private StringBuilder buildPathPrefix(Class beanClass) { StringBuilder pathMapping = new StringBuilder(); if (this.pathPrefix != null) { pathMapping.append(this.pathPrefix); pathMapping.append("/"); } else { pathMapping.append("/"); } if (this.basePackage != null) { String packageName = ClassUtils.getPackageName(beanClass); if (packageName.startsWith(this.basePackage)) { String subPackage = packageName.substring(this.basePackage.length()).replace('.', '/'); pathMapping.append(this.caseSensitive ? subPackage : subPackage.toLowerCase()); pathMapping.append("/"); } } return pathMapping; } // AbstractControllerUrlHandlerMapping
predicate.isMultiActionControllerType詳細完成看下面的ControllerTypePredicate
/** * Determine whether the given bean class indicates a controller type * that dispatches to multiple action methods. * @param beanClass the class to introspect */ protected boolean isMultiActionControllerType(Class beanClass) { return this.predicate.isMultiActionControllerType(beanClass); }
以上所述是小編給年夜家引見的SpringMVC源碼解讀之 HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化的相干常識,願望對年夜家有所贊助!