Home » spring-framework-2.5.4 » org.springframework » beans » factory » support » [javadoc | source]
    1   /*
    2    * Copyright 2002-2008 the original author or authors.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.springframework.beans.factory.support;
   18   
   19   import java.util.ArrayList;
   20   import java.util.Collection;
   21   import java.util.HashMap;
   22   import java.util.Iterator;
   23   import java.util.LinkedHashMap;
   24   import java.util.List;
   25   import java.util.Map;
   26   import java.util.Set;
   27   
   28   import org.springframework.beans.BeansException;
   29   import org.springframework.beans.FatalBeanException;
   30   import org.springframework.beans.TypeConverter;
   31   import org.springframework.beans.factory.BeanCreationException;
   32   import org.springframework.beans.factory.BeanCurrentlyInCreationException;
   33   import org.springframework.beans.factory.BeanDefinitionStoreException;
   34   import org.springframework.beans.factory.BeanFactory;
   35   import org.springframework.beans.factory.BeanFactoryUtils;
   36   import org.springframework.beans.factory.CannotLoadBeanClassException;
   37   import org.springframework.beans.factory.FactoryBean;
   38   import org.springframework.beans.factory.NoSuchBeanDefinitionException;
   39   import org.springframework.beans.factory.ObjectFactory;
   40   import org.springframework.beans.factory.SmartFactoryBean;
   41   import org.springframework.beans.factory.config.BeanDefinition;
   42   import org.springframework.beans.factory.config.BeanDefinitionHolder;
   43   import org.springframework.beans.factory.config.ConfigurableBeanFactory;
   44   import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
   45   import org.springframework.beans.factory.config.DependencyDescriptor;
   46   import org.springframework.core.CollectionFactory;
   47   import org.springframework.util.Assert;
   48   import org.springframework.util.ObjectUtils;
   49   import org.springframework.util.StringUtils;
   50   
   51   /**
   52    * Default implementation of the
   53    * {@link org.springframework.beans.factory.ListableBeanFactory} and
   54    * {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
   55    * based on bean definition objects.
   56    *
   57    * <p>Typical usage is registering all bean definitions first (possibly read
   58    * from a bean definition file), before accessing beans. Bean definition lookup
   59    * is therefore an inexpensive operation in a local bean definition table,
   60    * operating on pre-built bean definition metadata objects.
   61    *
   62    * <p>Can be used as a standalone bean factory, or as a superclass for custom
   63    * bean factories. Note that readers for specific bean definition formats are
   64    * typically implemented separately rather than as bean factory subclasses:
   65    * see for example {@link PropertiesBeanDefinitionReader} and
   66    * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
   67    *
   68    * <p>For an alternative implementation of the
   69    * {@link org.springframework.beans.factory.ListableBeanFactory} interface,
   70    * have a look at {@link StaticListableBeanFactory}, which manages existing
   71    * bean instances rather than creating new ones based on bean definitions.
   72    *
   73    * @author Rod Johnson
   74    * @author Juergen Hoeller
   75    * @author Sam Brannen
   76    * @since 16 April 2001
   77    * @see StaticListableBeanFactory
   78    * @see PropertiesBeanDefinitionReader
   79    * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
   80    */
   81   public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
   82       implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
   83   
   84   	/** Whether to allow re-registration of a different definition with the same name */
   85   	private boolean allowBeanDefinitionOverriding = true;
   86   
   87   	/** Whether to allow eager class loading even for lazy-init beans */
   88   	private boolean allowEagerClassLoading = true;
   89   
   90   	/** Whether bean definition metadata may be cached for all beans */
   91   	private boolean configurationFrozen = false;
   92   
   93   	/** Map of bean definition objects, keyed by bean name */
   94   	private final Map beanDefinitionMap = CollectionFactory.createConcurrentMapIfPossible(16);
   95   
   96   	/** List of bean definition names, in registration order */
   97   	private final List beanDefinitionNames = new ArrayList();
   98   
   99   	/** Cached array of bean definition names in case of frozen configuration */
  100   	private String[] frozenBeanDefinitionNames;
  101   
  102   	/** Resolver to use for checking if a bean definition is an autowire candidate */
  103   	private AutowireCandidateResolver autowireCandidateResolver = AutowireUtils.createAutowireCandidateResolver();
  104   
  105   	/** Map from dependency type to corresponding autowired value */
  106   	private final Map resolvableDependencies = new HashMap();
  107   
  108   
  109   	/**
  110   	 * Create a new DefaultListableBeanFactory.
  111   	 */
  112   	public DefaultListableBeanFactory() {
  113   		super();
  114   	}
  115   
  116   	/**
  117   	 * Create a new DefaultListableBeanFactory with the given parent.
  118   	 * @param parentBeanFactory the parent BeanFactory
  119   	 */
  120   	public DefaultListableBeanFactory(BeanFactory parentBeanFactory) {
  121   		super(parentBeanFactory);
  122   	}
  123   
  124   
  125   	/**
  126   	 * Set a custom autowire candidate resolver for this BeanFactory to use
  127   	 * when deciding whether a bean definition should be considered as a
  128   	 * candidate for autowiring.
  129   	 */
  130   	public void setAutowireCandidateResolver(AutowireCandidateResolver autowireCandidateResolver) {
  131   		Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null");
  132   		this.autowireCandidateResolver = autowireCandidateResolver;
  133   	}
  134   
  135   	/**
  136   	 * Return the autowire candidate resolver for this BeanFactory (never <code>null</code>).
  137   	 */
  138   	public AutowireCandidateResolver getAutowireCandidateResolver() {
  139   		return this.autowireCandidateResolver;
  140   	}
  141   
  142   	/**
  143   	 * Set whether it should be allowed to override bean definitions by registering
  144   	 * a different definition with the same name, automatically replacing the former.
  145   	 * If not, an exception will be thrown. This also applies to overriding aliases.
  146   	 * <p>Default is "true".
  147   	 * @see #registerBeanDefinition
  148   	 */
  149   	public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
  150   		this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
  151   	}
  152   
  153   	/**
  154   	 * Set whether the factory is allowed to eagerly load bean classes
  155   	 * even for bean definitions that are marked as "lazy-init".
  156   	 * <p>Default is "true". Turn this flag off to suppress class loading
  157   	 * for lazy-init beans unless such a bean is explicitly requested.
  158   	 * In particular, by-type lookups will then simply ignore bean definitions
  159   	 * without resolved class name, instead of loading the bean classes on
  160   	 * demand just to perform a type check.
  161   	 * @see AbstractBeanDefinition#setLazyInit
  162   	 */
  163   	public void setAllowEagerClassLoading(boolean allowEagerClassLoading) {
  164   		this.allowEagerClassLoading = allowEagerClassLoading;
  165   	}
  166   
  167   
  168   	public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
  169   		super.copyConfigurationFrom(otherFactory);
  170   		if (otherFactory instanceof DefaultListableBeanFactory) {
  171   			DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory;
  172   			this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding;
  173   			this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading;
  174   		}
  175   	}
  176   
  177   
  178   	//---------------------------------------------------------------------
  179   	// Implementation of ListableBeanFactory interface
  180   	//---------------------------------------------------------------------
  181   
  182   	public boolean containsBeanDefinition(String beanName) {
  183   		return this.beanDefinitionMap.containsKey(beanName);
  184   	}
  185   
  186   	public int getBeanDefinitionCount() {
  187   		return this.beanDefinitionMap.size();
  188   	}
  189   
  190   	public String[] getBeanDefinitionNames() {
  191   		synchronized (this.beanDefinitionMap) {
  192   			if (this.frozenBeanDefinitionNames != null) {
  193   				return this.frozenBeanDefinitionNames;
  194   			}
  195   			else {
  196   				return StringUtils.toStringArray(this.beanDefinitionNames);
  197   			}
  198   		}
  199   	}
  200   
  201   	public String[] getBeanNamesForType(Class type) {
  202   		return getBeanNamesForType(type, true, true);
  203   	}
  204   
  205   	public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) {
  206   		List result = new ArrayList();
  207   
  208   		// Check all bean definitions.
  209   		String[] beanDefinitionNames = getBeanDefinitionNames();
  210   		for (int i = 0; i < beanDefinitionNames.length; i++) {
  211   			String beanName = beanDefinitionNames[i];
  212   			// Only consider bean as eligible if the bean name
  213   			// is not defined as alias for some other bean.
  214   			if (!isAlias(beanName)) {
  215   				try {
  216   					RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  217   					// Only check bean definition if it is complete.
  218   					if (!mbd.isAbstract() &&
  219   							(allowEagerInit || ((mbd.hasBeanClass() || !mbd.isLazyInit() || this.allowEagerClassLoading)) &&
  220   									!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
  221   						// In case of FactoryBean, match object created by FactoryBean.
  222   						boolean isFactoryBean = isFactoryBean(beanName, mbd);
  223   						boolean matchFound =
  224   								(allowEagerInit || !isFactoryBean || containsSingleton(beanName)) &&
  225   								(includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type);
  226   						if (!matchFound && isFactoryBean) {
  227   							// In case of FactoryBean, try to match FactoryBean instance itself next.
  228   							beanName = FACTORY_BEAN_PREFIX + beanName;
  229   							matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
  230   						}
  231   						if (matchFound) {
  232   							result.add(beanName);
  233   						}
  234   					}
  235   				}
  236   				catch (CannotLoadBeanClassException ex) {
  237   					if (allowEagerInit) {
  238   						throw ex;
  239   					}
  240   					// Probably contains a placeholder: let's ignore it for type matching purposes.
  241   					if (this.logger.isDebugEnabled()) {
  242   						this.logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex);
  243   					}
  244   					onSuppressedException(ex);
  245   				}
  246   				catch (BeanDefinitionStoreException ex) {
  247   					if (allowEagerInit) {
  248   						throw ex;
  249   					}
  250   					// Probably contains a placeholder: let's ignore it for type matching purposes.
  251   					if (this.logger.isDebugEnabled()) {
  252   						this.logger.debug("Ignoring unresolvable metadata in bean definition '" + beanName + "'", ex);
  253   					}
  254   					onSuppressedException(ex);
  255   				}
  256   			}
  257   		}
  258   
  259   		// Check singletons too, to catch manually registered singletons.
  260   		String[] singletonNames = getSingletonNames();
  261   		for (int i = 0; i < singletonNames.length; i++) {
  262   			String beanName = singletonNames[i];
  263   			// Only check if manually registered.
  264   			if (!containsBeanDefinition(beanName)) {
  265   				// In case of FactoryBean, match object created by FactoryBean.
  266   				if (isFactoryBean(beanName)) {
  267   					if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
  268   						result.add(beanName);
  269   						// Match found for this bean: do not match FactoryBean itself anymore.
  270   						continue;
  271   					}
  272   					// In case of FactoryBean, try to match FactoryBean itself next.
  273   					beanName = FACTORY_BEAN_PREFIX + beanName;
  274   				}
  275   				// Match raw bean instance (might be raw FactoryBean).
  276   				if (isTypeMatch(beanName, type)) {
  277   					result.add(beanName);
  278   				}
  279   			}
  280   		}
  281   
  282   		return StringUtils.toStringArray(result);
  283   	}
  284   
  285   	/**
  286   	 * Check whether the specified bean would need to be eagerly initialized
  287   	 * in order to determine its type.
  288   	 * @param factoryBeanName a factory-bean reference that the bean definition
  289   	 * defines a factory method for
  290   	 * @return whether eager initialization is necessary
  291   	 */
  292   	private boolean requiresEagerInitForType(String factoryBeanName) {
  293   		return (factoryBeanName != null && isFactoryBean(factoryBeanName) && !containsSingleton(factoryBeanName));
  294   	}
  295   
  296   	public Map getBeansOfType(Class type) throws BeansException {
  297   		return getBeansOfType(type, true, true);
  298   	}
  299   
  300   	public Map getBeansOfType(Class type, boolean includeNonSingletons, boolean allowEagerInit)
  301   			throws BeansException {
  302   
  303   		String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
  304   		Map result = new LinkedHashMap(beanNames.length);
  305   		for (int i = 0; i < beanNames.length; i++) {
  306   			String beanName = beanNames[i];
  307   			try {
  308   				result.put(beanName, getBean(beanName));
  309   			}
  310   			catch (BeanCreationException ex) {
  311   				Throwable rootCause = ex.getMostSpecificCause();
  312   				if (rootCause instanceof BeanCurrentlyInCreationException) {
  313   					BeanCreationException bce = (BeanCreationException) rootCause;
  314   					if (isCurrentlyInCreation(bce.getBeanName())) {
  315   						if (this.logger.isDebugEnabled()) {
  316   							this.logger.debug("Ignoring match to currently created bean '" + beanName + "': " + ex.getMessage());
  317   						}
  318   						onSuppressedException(ex);
  319   						// Ignore: indicates a circular reference when autowiring constructors.
  320   						// We want to find matches other than the currently created bean itself.
  321   						continue;
  322   					}
  323   				}
  324   				throw ex;
  325   			}
  326   		}
  327   		return result;
  328   	}
  329   
  330   
  331   	//---------------------------------------------------------------------
  332   	// Implementation of ConfigurableListableBeanFactory interface
  333   	//---------------------------------------------------------------------
  334   
  335   	public void registerResolvableDependency(Class dependencyType, Object autowiredValue) {
  336   		Assert.notNull(dependencyType, "Type must not be null");
  337   		if (autowiredValue != null) {
  338   			Assert.isTrue((autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue)),
  339   					"Value [" + autowiredValue + "] does not implement specified type [" + dependencyType.getName() + "]");
  340   			this.resolvableDependencies.put(dependencyType, autowiredValue);
  341   		}
  342   	}
  343   
  344   	public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
  345   			throws NoSuchBeanDefinitionException {
  346   
  347   		// Consider FactoryBeans as autowiring candidates.
  348   		boolean isFactoryBean = (descriptor != null && descriptor.getDependencyType() != null &&
  349   				FactoryBean.class.isAssignableFrom(descriptor.getDependencyType()));
  350   		if (isFactoryBean) {
  351   			beanName = BeanFactoryUtils.transformedBeanName(beanName);
  352   		}
  353   
  354   		if (!containsBeanDefinition(beanName)) {
  355   			if (containsSingleton(beanName)) {
  356   				return true;
  357   			}
  358   			else if (getParentBeanFactory() instanceof ConfigurableListableBeanFactory) {
  359   				// No bean definition found in this factory -> delegate to parent.
  360   				return ((ConfigurableListableBeanFactory) getParentBeanFactory()).isAutowireCandidate(beanName, descriptor);
  361   			}
  362   		}
  363   
  364   		return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanName), descriptor);
  365   	}
  366   
  367   	/**
  368   	 * Determine whether the specified bean definition qualifies as an autowire candidate,
  369   	 * to be injected into other beans which declare a dependency of matching type.
  370   	 * @param beanName the name of the bean definition to check
  371   	 * @param mbd the merged bean definition to check
  372   	 * @param descriptor the descriptor of the dependency to resolve
  373   	 * @return whether the bean should be considered as autowire candidate
  374   	 */
  375   	protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, DependencyDescriptor descriptor) {
  376   		resolveBeanClass(mbd, beanName);
  377   		return getAutowireCandidateResolver().isAutowireCandidate(
  378   				new BeanDefinitionHolder(mbd, beanName, getAliases(beanName)), descriptor);
  379   	}
  380   
  381   	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
  382   		BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.get(beanName);
  383   		if (bd == null) {
  384   			if (this.logger.isTraceEnabled()) {
  385   				this.logger.trace("No bean named '" + beanName + "' found in " + this);
  386   			}
  387   			throw new NoSuchBeanDefinitionException(beanName);
  388   		}
  389   		return bd;
  390   	}
  391   
  392   	public void freezeConfiguration() {
  393   		this.configurationFrozen = true;
  394   		synchronized (this.beanDefinitionMap) {
  395   			this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
  396   		}
  397   	}
  398   
  399   	public boolean isConfigurationFrozen() {
  400   		return this.configurationFrozen;
  401   	}
  402   
  403   	/**
  404   	 * Considers all beans as eligible for metdata caching
  405   	 * if the factory's configuration has been marked as frozen.
  406   	 * @see #freezeConfiguration()
  407   	 */
  408   	protected boolean isBeanEligibleForMetadataCaching(String beanName) {
  409   		return (this.configurationFrozen || super.isBeanEligibleForMetadataCaching(beanName));
  410   	}
  411   
  412   	public void preInstantiateSingletons() throws BeansException {
  413   		if (this.logger.isInfoEnabled()) {
  414   			this.logger.info("Pre-instantiating singletons in " + this);
  415   		}
  416   
  417   		synchronized (this.beanDefinitionMap) {
  418   			for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
  419   				String beanName = (String) it.next();
  420   				RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
  421   				if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
  422   					if (isFactoryBean(beanName)) {
  423   						FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
  424   						if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
  425   							getBean(beanName);
  426   						}
  427   					}
  428   					else {
  429   						getBean(beanName);
  430   					}
  431   				}
  432   			}
  433   		}
  434   	}
  435   
  436   
  437   	//---------------------------------------------------------------------
  438   	// Implementation of BeanDefinitionRegistry interface
  439   	//---------------------------------------------------------------------
  440   
  441   	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  442   			throws BeanDefinitionStoreException {
  443   
  444   		Assert.hasText(beanName, "'beanName' must not be empty");
  445   		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  446   
  447   		if (beanDefinition instanceof AbstractBeanDefinition) {
  448   			try {
  449   				((AbstractBeanDefinition) beanDefinition).validate();
  450   			}
  451   			catch (BeanDefinitionValidationException ex) {
  452   				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  453   						"Validation of bean definition failed", ex);
  454   			}
  455   		}
  456   
  457   		synchronized (this.beanDefinitionMap) {
  458   			Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
  459   			if (oldBeanDefinition != null) {
  460   				if (!this.allowBeanDefinitionOverriding) {
  461   					throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  462   							"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
  463   							"': There is already [" + oldBeanDefinition + "] bound.");
  464   				}
  465   				else {
  466   					if (this.logger.isInfoEnabled()) {
  467   						this.logger.info("Overriding bean definition for bean '" + beanName +
  468   								"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
  469   					}
  470   				}
  471   			}
  472   			else {
  473   				this.beanDefinitionNames.add(beanName);
  474   				this.frozenBeanDefinitionNames = null;
  475   			}
  476   			this.beanDefinitionMap.put(beanName, beanDefinition);
  477   
  478   			resetBeanDefinition(beanName);
  479   		}
  480   	}
  481   
  482   	public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
  483   		Assert.hasText(beanName, "'beanName' must not be empty");
  484   
  485   		synchronized (this.beanDefinitionMap) {
  486   			BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.remove(beanName);
  487   			if (bd == null) {
  488   				if (this.logger.isTraceEnabled()) {
  489   					this.logger.trace("No bean named '" + beanName + "' found in " + this);
  490   				}
  491   				throw new NoSuchBeanDefinitionException(beanName);
  492   			}
  493   			this.beanDefinitionNames.remove(beanName);
  494   			this.frozenBeanDefinitionNames = null;
  495   
  496   			resetBeanDefinition(beanName);
  497   		}
  498   	}
  499   
  500   	/**
  501   	 * Reset all bean definition caches for the given bean,
  502   	 * including the caches of beans that are derived from it.
  503   	 * @param beanName the name of the bean to reset
  504   	 */
  505   	protected void resetBeanDefinition(String beanName) {
  506   		// Remove the merged bean definition for the given bean, if already created.
  507   		clearMergedBeanDefinition(beanName);
  508   
  509   		// Remove corresponding bean from singleton cache, if any. Shouldn't usually
  510   		// be necessary, rather just meant for overriding a context's default beans
  511   		// (e.g. the default StaticMessageSource in a StaticApplicationContext).
  512   		synchronized (getSingletonMutex()) {
  513   			destroySingleton(beanName);
  514   		}
  515   
  516   		// Reset all bean definitions that have the given bean as parent
  517   		// (recursively).
  518   		for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
  519   			String bdName = (String) it.next();
  520   			if (!beanName.equals(bdName)) {
  521   				BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.get(bdName);
  522   				if (beanName.equals(bd.getParentName())) {
  523   					resetBeanDefinition(bdName);
  524   				}
  525   			}
  526   		}
  527   	}
  528   
  529   	/**
  530   	 * Only allows alias overriding if bean definition overriding is allowed.
  531   	 */
  532   	protected boolean allowAliasOverriding() {
  533   		return this.allowBeanDefinitionOverriding;
  534   	}
  535   
  536   
  537   	//---------------------------------------------------------------------
  538   	// Implementation of superclass abstract methods
  539   	//---------------------------------------------------------------------
  540   
  541   	public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
  542   			Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException  {
  543   
  544   		Class type = descriptor.getDependencyType();
  545   		if (type.isArray()) {
  546   			Class componentType = type.getComponentType();
  547   			Map matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);
  548   			if (matchingBeans.isEmpty()) {
  549   				if (descriptor.isRequired()) {
  550   					raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
  551   				}
  552   				return null;
  553   			}
  554   			if (autowiredBeanNames != null) {
  555   				autowiredBeanNames.addAll(matchingBeans.keySet());
  556   			}
  557   			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
  558   			return converter.convertIfNecessary(matchingBeans.values(), type);
  559   		}
  560   		else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
  561   			Class elementType = descriptor.getCollectionType();
  562   			if (elementType == null) {
  563   				if (descriptor.isRequired()) {
  564   					throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
  565   				}
  566   				return null;
  567   			}
  568   			Map matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);
  569   			if (matchingBeans.isEmpty()) {
  570   				if (descriptor.isRequired()) {
  571   					raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
  572   				}
  573   				return null;
  574   			}
  575   			if (autowiredBeanNames != null) {
  576   				autowiredBeanNames.addAll(matchingBeans.keySet());
  577   			}
  578   			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
  579   			return converter.convertIfNecessary(matchingBeans.values(), type);
  580   		}
  581   		else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
  582   			Class keyType = descriptor.getMapKeyType();
  583   			if (keyType == null || !String.class.isAssignableFrom(keyType)) {
  584   				if (descriptor.isRequired()) {
  585   					throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
  586   							"] must be assignable to [java.lang.String]");
  587   				}
  588   				return null;
  589   			}
  590   			Class valueType = descriptor.getMapValueType();
  591   			if (valueType == null) {
  592   				if (descriptor.isRequired()) {
  593   					throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
  594   				}
  595   				return null;
  596   			}
  597   			Map matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
  598   			if (matchingBeans.isEmpty()) {
  599   				if (descriptor.isRequired()) {
  600   					raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
  601   				}
  602   				return null;
  603   			}
  604   			if (autowiredBeanNames != null) {
  605   				autowiredBeanNames.addAll(matchingBeans.keySet());
  606   			}
  607   			return matchingBeans;
  608   		}
  609   		else {
  610   			Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
  611   			if (matchingBeans.isEmpty()) {
  612   				if (descriptor.isRequired()) {
  613   					throw new NoSuchBeanDefinitionException(type,
  614   							"Unsatisfied dependency of type [" + type + "]: expected at least 1 matching bean");
  615   				}
  616   				return null;
  617   			}
  618   			if (matchingBeans.size() > 1) {
  619   				String primaryBeanName = determinePrimaryCandidate(matchingBeans, type);
  620   				if (primaryBeanName == null) {
  621   					throw new NoSuchBeanDefinitionException(type,
  622   							"expected single matching bean but found " + matchingBeans.size() + ": " + matchingBeans.keySet());
  623   				}
  624   				if (autowiredBeanNames != null) {
  625   					autowiredBeanNames.add(primaryBeanName);
  626   				}
  627   				return matchingBeans.get(primaryBeanName);
  628   			}
  629   			// We have exactly one match.
  630   			Map.Entry entry = (Map.Entry) matchingBeans.entrySet().iterator().next();
  631   			if (autowiredBeanNames != null) {
  632   				autowiredBeanNames.add(entry.getKey());
  633   			}
  634   			return entry.getValue();
  635   		}
  636   	}
  637   
  638   	/**
  639   	 * Find bean instances that match the required type.
  640   	 * Called during autowiring for the specified bean.
  641   	 * @param beanName the name of the bean that is about to be wired
  642   	 * @param requiredType the actual type of bean to look for
  643   	 * (may be an array component type or collection element type)
  644   	 * @param descriptor the descriptor of the dependency to resolve
  645   	 * @return a Map of candidate names and candidate instances that match
  646   	 * the required type (never <code>null</code>)
  647   	 * @throws BeansException in case of errors
  648   	 * @see #autowireByType
  649   	 * @see #autowireConstructor
  650   	 */
  651   	protected Map findAutowireCandidates(String beanName, Class requiredType, DependencyDescriptor descriptor) {
  652   		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  653   				this, requiredType, true, descriptor.isEager());
  654   		Map result = new LinkedHashMap(candidateNames.length);
  655   		for (Iterator it = this.resolvableDependencies.keySet().iterator(); it.hasNext();) {
  656   			Class autowiringType = (Class) it.next();
  657   			if (autowiringType.isAssignableFrom(requiredType)) {
  658   				Object autowiringValue = this.resolvableDependencies.get(autowiringType);
  659   				if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
  660   					autowiringValue = ((ObjectFactory) autowiringValue).getObject();
  661   				}
  662   				if (requiredType.isInstance(autowiringValue)) {
  663   					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
  664   					break;
  665   				}
  666   			}
  667   		}
  668   		for (int i = 0; i < candidateNames.length; i++) {
  669   			String candidateName = candidateNames[i];
  670   			if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
  671   				result.put(candidateName, getBean(candidateName));
  672   			}
  673   		}
  674   		return result;
  675   	}
  676   
  677   	/**
  678   	 * Determine the primary autowire candidate in the given set of beans.
  679   	 * @param candidateBeans a Map of candidate names and candidate instances
  680   	 * that match the required type, as returned by {@link #findAutowireCandidates}
  681   	 * @param type the required type
  682   	 * @return the name of the primary candidate, or <code>null</code> if none found
  683   	 */
  684   	protected String determinePrimaryCandidate(Map candidateBeans, Class type) {
  685   		String primaryBeanName = null;
  686   		for (Iterator it = candidateBeans.entrySet().iterator(); it.hasNext();) {
  687   			Map.Entry entry = (Map.Entry) it.next();
  688   			String candidateBeanName = (String) entry.getKey();
  689   			if (isPrimary(candidateBeanName, entry.getValue())) {
  690   				if (primaryBeanName != null) {
  691   					throw new NoSuchBeanDefinitionException(type,
  692   							"more than one 'primary' bean found among candidates: " + candidateBeans.keySet());
  693   				}
  694   				primaryBeanName = candidateBeanName;
  695   			}
  696   		}
  697   		return primaryBeanName;
  698   	}
  699   
  700   	/**
  701   	 * Return whether the bean definition for the given bean name has been
  702   	 * marked as a primary bean.
  703   	 * @param beanName the name of the bean
  704   	 * @param beanInstance the corresponding bean instance
  705   	 * @return whether the given bean qualifies as primary
  706   	 */
  707   	protected boolean isPrimary(String beanName, Object beanInstance) {
  708   		return ((containsBeanDefinition(beanName) && getMergedLocalBeanDefinition(beanName).isPrimary()) ||
  709   				this.resolvableDependencies.values().contains(beanInstance));
  710   	}
  711   
  712   	/**
  713   	 * Raise a NoSuchBeanDefinitionException for an unresolvable dependency.
  714   	 */
  715   	private void raiseNoSuchBeanDefinitionException(
  716   			Class type, String dependencyDescription, DependencyDescriptor descriptor)
  717   			throws NoSuchBeanDefinitionException {
  718   
  719   		throw new NoSuchBeanDefinitionException(type, dependencyDescription,
  720   				"expected at least 1 bean which qualifies as autowire candidate for this dependency. " +
  721   				"Dependency annotations: " + ObjectUtils.nullSafeToString(descriptor.getAnnotations()));
  722   	}
  723   
  724   
  725   	public String toString() {
  726   		StringBuffer sb = new StringBuffer(ObjectUtils.identityToString(this));
  727   		sb.append(": defining beans [");
  728   		sb.append(StringUtils.arrayToCommaDelimitedString(getBeanDefinitionNames()));
  729   		sb.append("]; ");
  730   		BeanFactory parent = getParentBeanFactory();
  731   		if (parent == null) {
  732   			sb.append("root of factory hierarchy");
  733   		}
  734   		else {
  735   			sb.append("parent: " + ObjectUtils.identityToString(parent));
  736   		}
  737   		return sb.toString();
  738   	}
  739   
  740   }

Save This Page
Home » spring-framework-2.5.4 » org.springframework » beans » factory » support » [javadoc | source]