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.ApplicationContextException; 022import org.springframework.util.ObjectUtils; 023 024/** 025 * Abstract implementation of the {@link org.springframework.web.servlet.HandlerMapping} 026 * interface, detecting URL mappings for handler beans through introspection of all 027 * defined beans in the application context. 028 * 029 * @author Juergen Hoeller 030 * @since 2.5 031 * @see #determineUrlsForHandler 032 */ 033public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping { 034 035 private boolean detectHandlersInAncestorContexts = false; 036 037 038 /** 039 * Set whether to detect handler beans in ancestor ApplicationContexts. 040 * <p>Default is "false": Only handler beans in the current ApplicationContext 041 * will be detected, i.e. only in the context that this HandlerMapping itself 042 * is defined in (typically the current DispatcherServlet's context). 043 * <p>Switch this flag on to detect handler beans in ancestor contexts 044 * (typically the Spring root WebApplicationContext) as well. 045 */ 046 public void setDetectHandlersInAncestorContexts(boolean detectHandlersInAncestorContexts) { 047 this.detectHandlersInAncestorContexts = detectHandlersInAncestorContexts; 048 } 049 050 051 /** 052 * Calls the {@link #detectHandlers()} method in addition to the 053 * superclass's initialization. 054 */ 055 @Override 056 public void initApplicationContext() throws ApplicationContextException { 057 super.initApplicationContext(); 058 detectHandlers(); 059 } 060 061 /** 062 * Register all handlers found in the current ApplicationContext. 063 * <p>The actual URL determination for a handler is up to the concrete 064 * {@link #determineUrlsForHandler(String)} implementation. A bean for 065 * which no such URLs could be determined is simply not considered a handler. 066 * @throws org.springframework.beans.BeansException if the handler couldn't be registered 067 * @see #determineUrlsForHandler(String) 068 */ 069 protected void detectHandlers() throws BeansException { 070 if (logger.isDebugEnabled()) { 071 logger.debug("Looking for URL mappings in application context: " + getApplicationContext()); 072 } 073 String[] beanNames = (this.detectHandlersInAncestorContexts ? 074 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : 075 getApplicationContext().getBeanNamesForType(Object.class)); 076 077 // Take any bean name that we can determine URLs for. 078 for (String beanName : beanNames) { 079 String[] urls = determineUrlsForHandler(beanName); 080 if (!ObjectUtils.isEmpty(urls)) { 081 // URL paths found: Let's consider it a handler. 082 registerHandler(urls, beanName); 083 } 084 else { 085 if (logger.isDebugEnabled()) { 086 logger.debug("Rejected bean name '" + beanName + "': no URL paths identified"); 087 } 088 } 089 } 090 } 091 092 093 /** 094 * Determine the URLs for the given handler bean. 095 * @param beanName the name of the candidate bean 096 * @return the URLs determined for the bean, 097 * or {@code null} or an empty array if none 098 */ 099 protected abstract String[] determineUrlsForHandler(String beanName); 100 101}