001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.beans.factory.support;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.LinkedHashMap;
023: import java.util.List;
024: import java.util.Map;
025:
026: import org.springframework.beans.BeansException;
027: import org.springframework.beans.factory.BeanCreationException;
028: import org.springframework.beans.factory.BeanCurrentlyInCreationException;
029: import org.springframework.beans.factory.BeanDefinitionStoreException;
030: import org.springframework.beans.factory.BeanFactory;
031: import org.springframework.beans.factory.BeanFactoryUtils;
032: import org.springframework.beans.factory.CannotLoadBeanClassException;
033: import org.springframework.beans.factory.FactoryBean;
034: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
035: import org.springframework.beans.factory.SmartFactoryBean;
036: import org.springframework.beans.factory.config.BeanDefinition;
037: import org.springframework.beans.factory.config.BeanDefinitionHolder;
038: import org.springframework.beans.factory.config.ConfigurableBeanFactory;
039: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
040: import org.springframework.beans.factory.config.DependencyDescriptor;
041: import org.springframework.core.CollectionFactory;
042: import org.springframework.util.Assert;
043: import org.springframework.util.ObjectUtils;
044: import org.springframework.util.StringUtils;
045:
046: /**
047: * Default implementation of the
048: * {@link org.springframework.beans.factory.ListableBeanFactory} and
049: * {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
050: * based on bean definition objects.
051: *
052: * <p>Typical usage is registering all bean definitions first (possibly read
053: * from a bean definition file), before accessing beans. Bean definition lookup
054: * is therefore an inexpensive operation in a local bean definition table,
055: * operating on pre-built bean definition metadata objects.
056: *
057: * <p>Can be used as a standalone bean factory, or as a superclass for custom
058: * bean factories. Note that readers for specific bean definition formats are
059: * typically implemented separately rather than as bean factory subclasses:
060: * see for example {@link PropertiesBeanDefinitionReader} and
061: * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
062: *
063: * <p>For an alternative implementation of the
064: * {@link org.springframework.beans.factory.ListableBeanFactory} interface,
065: * have a look at {@link StaticListableBeanFactory}, which manages existing
066: * bean instances rather than creating new ones based on bean definitions.
067: *
068: * @author Rod Johnson
069: * @author Juergen Hoeller
070: * @author Sam Brannen
071: * @since 16 April 2001
072: * @see StaticListableBeanFactory
073: * @see PropertiesBeanDefinitionReader
074: * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
075: */
076: public class DefaultListableBeanFactory extends
077: AbstractAutowireCapableBeanFactory implements
078: ConfigurableListableBeanFactory, BeanDefinitionRegistry {
079:
080: /** Whether to allow re-registration of a different definition with the same name */
081: private boolean allowBeanDefinitionOverriding = true;
082:
083: /** Whether to allow eager class loading even for lazy-init beans */
084: private boolean allowEagerClassLoading = true;
085:
086: /** Map of bean definition objects, keyed by bean name */
087: private final Map beanDefinitionMap = CollectionFactory
088: .createConcurrentMapIfPossible(16);
089:
090: /** List of bean definition names, in registration order */
091: private final List beanDefinitionNames = new ArrayList();
092:
093: /** Resolver to use for checking if a bean definition is an autowire candidate */
094: private AutowireCandidateResolver autowireCandidateResolver = AutowireUtils
095: .createAutowireCandidateResolver();
096:
097: /** Map from dependency type to corresponding autowired value */
098: private final Map resolvableDependencies = new HashMap();
099:
100: /**
101: * Create a new DefaultListableBeanFactory.
102: */
103: public DefaultListableBeanFactory() {
104: super ();
105: }
106:
107: /**
108: * Create a new DefaultListableBeanFactory with the given parent.
109: * @param parentBeanFactory the parent BeanFactory
110: */
111: public DefaultListableBeanFactory(BeanFactory parentBeanFactory) {
112: super (parentBeanFactory);
113: }
114:
115: /**
116: * Set a custom autowire candidate resolver for this BeanFactory to use
117: * when deciding whether a bean definition should be considered as a
118: * candidate for autowiring.
119: */
120: public void setAutowireCandidateResolver(
121: AutowireCandidateResolver autowireCandidateResolver) {
122: Assert.notNull(autowireCandidateResolver,
123: "AutowireCandidateResolver must not be null");
124: this .autowireCandidateResolver = autowireCandidateResolver;
125: }
126:
127: /**
128: * Return the autowire candidate resolver for this BeanFactory (never <code>null</code>).
129: */
130: public AutowireCandidateResolver getAutowireCandidateResolver() {
131: return this .autowireCandidateResolver;
132: }
133:
134: /**
135: * Set whether it should be allowed to override bean definitions by registering
136: * a different definition with the same name, automatically replacing the former.
137: * If not, an exception will be thrown. Default is "true".
138: */
139: public void setAllowBeanDefinitionOverriding(
140: boolean allowBeanDefinitionOverriding) {
141: this .allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
142: }
143:
144: /**
145: * Set whether the factory is allowed to eagerly load bean classes
146: * even for bean definitions that are marked as "lazy-init".
147: * <p>Default is "true". Turn this flag off to suppress class loading
148: * for lazy-init beans unless such a bean is explicitly requested.
149: * In particular, by-type lookups will then simply ignore bean definitions
150: * without resolved class name, instead of loading the bean classes on
151: * demand just to perform a type check.
152: * @see AbstractBeanDefinition#setLazyInit
153: */
154: public void setAllowEagerClassLoading(boolean allowEagerClassLoading) {
155: this .allowEagerClassLoading = allowEagerClassLoading;
156: }
157:
158: public void copyConfigurationFrom(
159: ConfigurableBeanFactory otherFactory) {
160: super .copyConfigurationFrom(otherFactory);
161: if (otherFactory instanceof DefaultListableBeanFactory) {
162: DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory;
163: this .allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding;
164: this .allowEagerClassLoading = otherListableFactory.allowEagerClassLoading;
165: }
166: }
167:
168: //---------------------------------------------------------------------
169: // Implementation of ListableBeanFactory interface
170: //---------------------------------------------------------------------
171:
172: public boolean containsBeanDefinition(String beanName) {
173: return this .beanDefinitionMap.containsKey(beanName);
174: }
175:
176: public int getBeanDefinitionCount() {
177: return this .beanDefinitionMap.size();
178: }
179:
180: public String[] getBeanDefinitionNames() {
181: synchronized (this .beanDefinitionMap) {
182: return StringUtils.toStringArray(this .beanDefinitionNames);
183: }
184: }
185:
186: public String[] getBeanNamesForType(Class type) {
187: return getBeanNamesForType(type, true, true);
188: }
189:
190: public String[] getBeanNamesForType(Class type,
191: boolean includePrototypes, boolean allowEagerInit) {
192: List result = new ArrayList();
193:
194: // Check all bean definitions.
195: String[] beanDefinitionNames = null;
196: synchronized (this .beanDefinitionMap) {
197: beanDefinitionNames = StringUtils
198: .toStringArray(this .beanDefinitionNames);
199: }
200: for (int i = 0; i < beanDefinitionNames.length; i++) {
201: String beanName = beanDefinitionNames[i];
202: // Only consider bean as eligible if the bean name
203: // is not defined as alias for some other bean.
204: if (!isAlias(beanName)) {
205: try {
206: RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
207: // Only check bean definition if it is complete.
208: if (!mbd.isAbstract()
209: && (allowEagerInit || mbd.hasBeanClass()
210: || !mbd.isLazyInit() || this .allowEagerClassLoading)) {
211: // In case of FactoryBean, match object created by FactoryBean.
212: Class beanClass = predictBeanType(beanName,
213: mbd, true);
214: boolean isFactoryBean = (beanClass != null && FactoryBean.class
215: .isAssignableFrom(beanClass));
216: boolean matchFound = (allowEagerInit || !requiresEagerInitForType(
217: beanName, isFactoryBean, mbd
218: .getFactoryBeanName()))
219: && (includePrototypes || isSingleton(beanName))
220: && isTypeMatch(beanName, type);
221: if (!matchFound && isFactoryBean) {
222: // In case of FactoryBean, try to match FactoryBean instance itself next.
223: beanName = FACTORY_BEAN_PREFIX + beanName;
224: matchFound = (includePrototypes || mbd
225: .isSingleton())
226: && isTypeMatch(beanName, type);
227: }
228: if (matchFound) {
229: result.add(beanName);
230: }
231: }
232: } catch (CannotLoadBeanClassException ex) {
233: if (allowEagerInit) {
234: throw ex;
235: }
236: // Probably contains a placeholder: let's ignore it for type matching purposes.
237: if (this .logger.isDebugEnabled()) {
238: this .logger.debug(
239: "Ignoring bean class loading failure for bean '"
240: + beanName + "'", ex);
241: }
242: onSuppressedException(ex);
243: } catch (BeanDefinitionStoreException ex) {
244: if (allowEagerInit) {
245: throw ex;
246: }
247: // Probably contains a placeholder: let's ignore it for type matching purposes.
248: if (this .logger.isDebugEnabled()) {
249: this .logger.debug(
250: "Ignoring unresolvable metadata in bean definition '"
251: + beanName + "'", ex);
252: }
253: onSuppressedException(ex);
254: }
255: }
256: }
257:
258: // Check singletons too, to catch manually registered singletons.
259: String[] singletonNames = getSingletonNames();
260: for (int i = 0; i < singletonNames.length; i++) {
261: String beanName = singletonNames[i];
262: // Only check if manually registered.
263: if (!containsBeanDefinition(beanName)) {
264: // In case of FactoryBean, match object created by FactoryBean.
265: if (isFactoryBean(beanName)) {
266: if ((includePrototypes || isSingleton(beanName))
267: && 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 beanName the name of the bean
289: * @param isFactoryBean whether the bean itself is a FactoryBean
290: * @param factoryBeanName a factory-bean reference that the bean definition
291: * defines a factory method for
292: * @return whether eager initialization is necessary
293: */
294: private boolean requiresEagerInitForType(String beanName,
295: boolean isFactoryBean, String factoryBeanName) {
296: return (isFactoryBean && !containsSingleton(beanName))
297: || (factoryBeanName != null
298: && isFactoryBean(factoryBeanName) && !containsSingleton(factoryBeanName));
299: }
300:
301: public Map getBeansOfType(Class type) throws BeansException {
302: return getBeansOfType(type, true, true);
303: }
304:
305: public Map getBeansOfType(Class type, boolean includePrototypes,
306: boolean allowEagerInit) throws BeansException {
307:
308: String[] beanNames = getBeanNamesForType(type,
309: includePrototypes, allowEagerInit);
310: Map result = new LinkedHashMap(beanNames.length);
311: for (int i = 0; i < beanNames.length; i++) {
312: String beanName = beanNames[i];
313: try {
314: result.put(beanName, getBean(beanName));
315: } catch (BeanCreationException ex) {
316: Throwable rootCause = ex.getMostSpecificCause();
317: if (rootCause instanceof BeanCurrentlyInCreationException) {
318: BeanCreationException bce = (BeanCreationException) rootCause;
319: if (isCurrentlyInCreation(bce.getBeanName())) {
320: if (this .logger.isDebugEnabled()) {
321: this .logger
322: .debug("Ignoring match to currently created bean '"
323: + beanName
324: + "': "
325: + ex.getMessage());
326: }
327: onSuppressedException(ex);
328: // Ignore: indicates a circular reference when autowiring constructors.
329: // We want to find matches other than the currently created bean itself.
330: continue;
331: }
332: }
333: throw ex;
334: }
335: }
336: return result;
337: }
338:
339: //---------------------------------------------------------------------
340: // Implementation of ConfigurableListableBeanFactory interface
341: //---------------------------------------------------------------------
342:
343: public void registerResolvableDependency(Class dependencyType,
344: Object autowiredValue) {
345: Assert.notNull(dependencyType, "Type must not be null");
346: Assert.isTrue(dependencyType.isInstance(autowiredValue),
347: "Value does not implement specified type");
348: this .resolvableDependencies.put(dependencyType, autowiredValue);
349: }
350:
351: public boolean isAutowireCandidate(String beanName,
352: DependencyDescriptor descriptor)
353: throws NoSuchBeanDefinitionException {
354:
355: // Consider FactoryBeans as autowiring candidates.
356: final boolean isFactoryBean = (descriptor != null)
357: && (descriptor.getDependencyType() != null)
358: && FactoryBean.class.isAssignableFrom(descriptor
359: .getDependencyType());
360: if (isFactoryBean) {
361: beanName = BeanFactoryUtils.transformedBeanName(beanName);
362: }
363:
364: if (!containsBeanDefinition(beanName)) {
365: if (containsSingleton(beanName)) {
366: return true;
367: } else if (getParentBeanFactory() instanceof ConfigurableListableBeanFactory) {
368: // No bean definition found in this factory -> delegate to parent.
369: return ((ConfigurableListableBeanFactory) getParentBeanFactory())
370: .isAutowireCandidate(beanName, descriptor);
371: }
372: }
373:
374: return isAutowireCandidate(beanName,
375: getMergedLocalBeanDefinition(beanName), descriptor);
376: }
377:
378: /**
379: * Determine whether the specified bean definition qualifies as an autowire candidate,
380: * to be injected into other beans which declare a dependency of matching type.
381: * @param beanName the name of the bean definition to check
382: * @param mbd the merged bean definition to check
383: * @param descriptor the descriptor of the dependency to resolve
384: * @return whether the bean should be considered as autowire candidate
385: */
386: protected boolean isAutowireCandidate(String beanName,
387: RootBeanDefinition mbd, DependencyDescriptor descriptor) {
388: return getAutowireCandidateResolver().isAutowireCandidate(
389: new BeanDefinitionHolder(mbd, beanName,
390: getAliases(beanName)), descriptor);
391: }
392:
393: public boolean isPrimary(String beanName, Object beanInstance) {
394: return (super .isPrimary(beanName, beanInstance) || this .resolvableDependencies
395: .values().contains(beanInstance));
396: }
397:
398: protected String determinePrimaryCandidate(Map candidateBeans,
399: Class type) {
400: String primaryBeanName = null;
401: for (Iterator it = candidateBeans.entrySet().iterator(); it
402: .hasNext();) {
403: Map.Entry entry = (Map.Entry) it.next();
404: String candidateBeanName = (String) entry.getKey();
405: if (isPrimary(candidateBeanName, entry.getValue())) {
406: if (primaryBeanName != null) {
407: throw new NoSuchBeanDefinitionException(type,
408: "more than one 'primary' bean found among candidates: "
409: + candidateBeans.keySet());
410: }
411: primaryBeanName = candidateBeanName;
412: }
413: }
414: return primaryBeanName;
415: }
416:
417: public BeanDefinition getBeanDefinition(String beanName)
418: throws NoSuchBeanDefinitionException {
419: BeanDefinition bd = (BeanDefinition) this .beanDefinitionMap
420: .get(beanName);
421: if (bd == null) {
422: if (this .logger.isTraceEnabled()) {
423: this .logger.trace("No bean named '" + beanName
424: + "' found in " + this );
425: }
426: throw new NoSuchBeanDefinitionException(beanName);
427: }
428: return bd;
429: }
430:
431: public void preInstantiateSingletons() throws BeansException {
432: if (this .logger.isInfoEnabled()) {
433: this .logger.info("Pre-instantiating singletons in " + this );
434: }
435:
436: synchronized (this .beanDefinitionMap) {
437: for (Iterator it = this .beanDefinitionNames.iterator(); it
438: .hasNext();) {
439: String beanName = (String) it.next();
440: RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
441: if (!bd.isAbstract() && bd.isSingleton()
442: && !bd.isLazyInit()) {
443: if (isFactoryBean(beanName)) {
444: FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX
445: + beanName);
446: if (factory instanceof SmartFactoryBean
447: && ((SmartFactoryBean) factory)
448: .isEagerInit()) {
449: getBean(beanName);
450: }
451: } else {
452: getBean(beanName);
453: }
454: }
455: }
456: }
457: }
458:
459: //---------------------------------------------------------------------
460: // Implementation of BeanDefinitionRegistry interface
461: //---------------------------------------------------------------------
462:
463: public void registerBeanDefinition(String beanName,
464: BeanDefinition beanDefinition)
465: throws BeanDefinitionStoreException {
466:
467: Assert.hasText(beanName, "'beanName' must not be empty");
468: Assert.notNull(beanDefinition,
469: "BeanDefinition must not be null");
470:
471: if (beanDefinition instanceof AbstractBeanDefinition) {
472: try {
473: ((AbstractBeanDefinition) beanDefinition).validate();
474: } catch (BeanDefinitionValidationException ex) {
475: throw new BeanDefinitionStoreException(beanDefinition
476: .getResourceDescription(), beanName,
477: "Validation of bean definition failed", ex);
478: }
479: }
480:
481: synchronized (this .beanDefinitionMap) {
482: Object oldBeanDefinition = this .beanDefinitionMap
483: .get(beanName);
484: if (oldBeanDefinition != null) {
485: if (!this .allowBeanDefinitionOverriding) {
486: throw new BeanDefinitionStoreException(
487: beanDefinition.getResourceDescription(),
488: beanName,
489: "Cannot register bean definition ["
490: + beanDefinition + "] for bean '"
491: + beanName
492: + "': There is already ["
493: + oldBeanDefinition + "] bound.");
494: } else {
495: if (this .logger.isInfoEnabled()) {
496: this .logger
497: .info("Overriding bean definition for bean '"
498: + beanName
499: + "': replacing ["
500: + oldBeanDefinition
501: + "] with ["
502: + beanDefinition
503: + "]");
504: }
505: }
506: } else {
507: this .beanDefinitionNames.add(beanName);
508: }
509: this .beanDefinitionMap.put(beanName, beanDefinition);
510:
511: resetBeanDefinition(beanName);
512: }
513: }
514:
515: public void removeBeanDefinition(String beanName)
516: throws NoSuchBeanDefinitionException {
517: Assert.hasText(beanName, "'beanName' must not be empty");
518:
519: synchronized (this .beanDefinitionMap) {
520: BeanDefinition bd = (BeanDefinition) this .beanDefinitionMap
521: .remove(beanName);
522: if (bd == null) {
523: if (this .logger.isTraceEnabled()) {
524: this .logger.trace("No bean named '" + beanName
525: + "' found in " + this );
526: }
527: throw new NoSuchBeanDefinitionException(beanName);
528: }
529: this .beanDefinitionNames.remove(beanName);
530:
531: resetBeanDefinition(beanName);
532: }
533: }
534:
535: /**
536: * Reset all bean definition caches for the given bean,
537: * including the caches of beans that are derived from it.
538: * @param beanName the name of the bean to reset
539: */
540: protected void resetBeanDefinition(String beanName) {
541: // Remove the merged bean definition for the given bean, if already created.
542: clearMergedBeanDefinition(beanName);
543:
544: // Remove corresponding bean from singleton cache, if any. Shouldn't usually
545: // be necessary, rather just meant for overriding a context's default beans
546: // (e.g. the default StaticMessageSource in a StaticApplicationContext).
547: synchronized (getSingletonMutex()) {
548: destroySingleton(beanName);
549: }
550:
551: // Reset all bean definitions that have the given bean as parent
552: // (recursively).
553: for (Iterator it = this .beanDefinitionNames.iterator(); it
554: .hasNext();) {
555: String bdName = (String) it.next();
556: if (!beanName.equals(bdName)) {
557: BeanDefinition bd = (BeanDefinition) this .beanDefinitionMap
558: .get(bdName);
559: if (beanName.equals(bd.getParentName())) {
560: resetBeanDefinition(bdName);
561: }
562: }
563: }
564: }
565:
566: //---------------------------------------------------------------------
567: // Implementation of superclass abstract methods
568: //---------------------------------------------------------------------
569:
570: protected Map findAutowireCandidates(String beanName,
571: Class requiredType, DependencyDescriptor descriptor) {
572: String[] candidateNames = BeanFactoryUtils
573: .beanNamesForTypeIncludingAncestors(this , requiredType);
574: Map result = new LinkedHashMap(candidateNames.length);
575: for (Iterator it = this .resolvableDependencies.keySet()
576: .iterator(); it.hasNext();) {
577: Class autowiringType = (Class) it.next();
578: if (autowiringType.isAssignableFrom(requiredType)) {
579: Object autowiringValue = this .resolvableDependencies
580: .get(autowiringType);
581: if (requiredType.isInstance(autowiringValue)) {
582: result.put(ObjectUtils
583: .identityToString(autowiringValue),
584: autowiringValue);
585: break;
586: }
587: }
588: }
589: for (int i = 0; i < candidateNames.length; i++) {
590: String candidateName = candidateNames[i];
591: if (!candidateName.equals(beanName)
592: && isAutowireCandidate(candidateName, descriptor)) {
593: result.put(candidateName, getBean(candidateName));
594: }
595: }
596: return result;
597: }
598:
599: public String toString() {
600: StringBuffer sb = new StringBuffer(ObjectUtils
601: .identityToString(this ));
602: sb.append(": defining beans [");
603: sb.append(StringUtils
604: .arrayToCommaDelimitedString(getBeanDefinitionNames()));
605: sb.append("]; ");
606: BeanFactory parent = getParentBeanFactory();
607: if (parent == null) {
608: sb.append("root of factory hierarchy");
609: } else {
610: sb
611: .append("parent: "
612: + ObjectUtils.identityToString(parent));
613: }
614: return sb.toString();
615: }
616:
617: }
|