001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.handler; 018 019import org.springframework.beans.BeansException; 020import org.springframework.beans.factory.BeanFactoryUtils; 021import org.springframework.context.ApplicationContext; 022import org.springframework.context.ApplicationContextException; 023import org.springframework.util.ObjectUtils; 024 025/** 026 * Abstract implementation of the {@link org.springframework.web.servlet.HandlerMapping} 027 * interface, detecting URL mappings for handler beans through introspection of all 028 * defined beans in the application context. 029 * 030 * @author Juergen Hoeller 031 * @since 2.5 032 * @see #determineUrlsForHandler 033 */ 034public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping { 035 036 private boolean detectHandlersInAncestorContexts = false; 037 038 039 /** 040 * Set whether to detect handler beans in ancestor ApplicationContexts. 041 * <p>Default is "false": Only handler beans in the current ApplicationContext 042 * will be detected, i.e. only in the context that this HandlerMapping itself 043 * is defined in (typically the current DispatcherServlet's context). 044 * <p>Switch this flag on to detect handler beans in ancestor contexts 045 * (typically the Spring root WebApplicationContext) as well. 046 */ 047 public void setDetectHandlersInAncestorContexts(boolean detectHandlersInAncestorContexts) { 048 this.detectHandlersInAncestorContexts = detectHandlersInAncestorContexts; 049 } 050 051 052 /** 053 * Calls the {@link #detectHandlers()} method in addition to the 054 * superclass's initialization. 055 */ 056 @Override 057 public void initApplicationContext() throws ApplicationContextException { 058 super.initApplicationContext(); 059 detectHandlers(); 060 } 061 062 /** 063 * Register all handlers found in the current ApplicationContext. 064 * <p>The actual URL determination for a handler is up to the concrete 065 * {@link #determineUrlsForHandler(String)} implementation. A bean for 066 * which no such URLs could be determined is simply not considered a handler. 067 * @throws org.springframework.beans.BeansException if the handler couldn't be registered 068 * @see #determineUrlsForHandler(String) 069 */ 070 protected void detectHandlers() throws BeansException { 071 ApplicationContext applicationContext = obtainApplicationContext(); 072 String[] beanNames = (this.detectHandlersInAncestorContexts ? 073 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) : 074 applicationContext.getBeanNamesForType(Object.class)); 075 076 // Take any bean name that we can determine URLs for. 077 for (String beanName : beanNames) { 078 String[] urls = determineUrlsForHandler(beanName); 079 if (!ObjectUtils.isEmpty(urls)) { 080 // URL paths found: Let's consider it a handler. 081 registerHandler(urls, beanName); 082 } 083 } 084 085 if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) { 086 logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName()); 087 } 088 } 089 090 091 /** 092 * Determine the URLs for the given handler bean. 093 * @param beanName the name of the candidate bean 094 * @return the URLs determined for the bean, or an empty array if none 095 */ 096 protected abstract String[] determineUrlsForHandler(String beanName); 097 098}