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 }