/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.servlet.handler; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.util.ObjectUtils; /** * Abstract implementation of the {@link org.springframework.web.servlet.HandlerMapping} * interface, detecting URL mappings for handler beans through introspection of all * defined beans in the application context. * * @author Juergen Hoeller * @since 2.5 * @see #determineUrlsForHandler */ public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping { private boolean detectHandlersInAncestorContexts = false; /** * Set whether to detect handler beans in ancestor ApplicationContexts. * <p>Default is "false": Only handler beans in the current ApplicationContext * will be detected, i.e. only in the context that this HandlerMapping itself * is defined in (typically the current DispatcherServlet's context). * <p>Switch this flag on to detect handler beans in ancestor contexts * (typically the Spring root WebApplicationContext) as well. */ public void setDetectHandlersInAncestorContexts(boolean detectHandlersInAncestorContexts) { this.detectHandlersInAncestorContexts = detectHandlersInAncestorContexts; } /** * Calls the {@link #detectHandlers()} method in addition to the * superclass's initialization. */ @Override public void initApplicationContext() throws ApplicationContextException { super.initApplicationContext(); detectHandlers(); } /** * 建立当前 ApplicationContext 中的所有 Controller 和 url 的对应关系 */ protected void detectHandlers() throws BeansException { ApplicationContext applicationContext = obtainApplicationContext(); // 获取 ApplicationContext 容器中所有 bean 的 Name String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) : applicationContext.getBeanNamesForType(Object.class)); // 遍历 beanNames,并找到这些 bean 对应的 url for (String beanName : beanNames) { // 找 bean 上的所有 url(Controller 上的 url+方法上的 url),该方法由对应的子类实现 String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { // // 保存 urls 和 beanName 的对应关系,put it to Map<urls,beanName> // 该方法在父类 AbstractUrlHandlerMapping中实现 registerHandler(urls, beanName); } } if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) { logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName()); } } /** *获取 Controller 中所有方法的 url,由子类实现,典型的模板模式 */ protected abstract String[] determineUrlsForHandler(String beanName); }