KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > support > AbstractBeanFactory


1 /*
2  * Copyright 2002-2007 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.beans.PropertyEditor JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Set JavaDoc;
29
30 import org.springframework.beans.BeanWrapper;
31 import org.springframework.beans.BeansException;
32 import org.springframework.beans.PropertyEditorRegistrar;
33 import org.springframework.beans.PropertyEditorRegistry;
34 import org.springframework.beans.PropertyValues;
35 import org.springframework.beans.SimpleTypeConverter;
36 import org.springframework.beans.TypeConverter;
37 import org.springframework.beans.TypeMismatchException;
38 import org.springframework.beans.factory.BeanCreationException;
39 import org.springframework.beans.factory.BeanCurrentlyInCreationException;
40 import org.springframework.beans.factory.BeanDefinitionStoreException;
41 import org.springframework.beans.factory.BeanFactory;
42 import org.springframework.beans.factory.BeanFactoryUtils;
43 import org.springframework.beans.factory.BeanIsAbstractException;
44 import org.springframework.beans.factory.BeanIsNotAFactoryException;
45 import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
46 import org.springframework.beans.factory.CannotLoadBeanClassException;
47 import org.springframework.beans.factory.DisposableBean;
48 import org.springframework.beans.factory.FactoryBean;
49 import org.springframework.beans.factory.FactoryBeanNotInitializedException;
50 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
51 import org.springframework.beans.factory.ObjectFactory;
52 import org.springframework.beans.factory.SmartFactoryBean;
53 import org.springframework.beans.factory.config.BeanDefinition;
54 import org.springframework.beans.factory.config.BeanPostProcessor;
55 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
56 import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
57 import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
58 import org.springframework.beans.factory.config.Scope;
59 import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
60 import org.springframework.core.CollectionFactory;
61 import org.springframework.core.MethodParameter;
62 import org.springframework.util.Assert;
63 import org.springframework.util.ClassUtils;
64 import org.springframework.util.StringUtils;
65
66 /**
67  * Abstract base class for {@link org.springframework.beans.factory.BeanFactory}
68  * implementations, providing the full capabilities of the
69  * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory} SPI.
70  * Does <i>not</i> assume a listable bean factory: can therefore also be used
71  * as base class for bean factory implementations which obtain bean definitions
72  * from some backend resource (where bean definition access is an expensive operation).
73  *
74  * <p>This class provides a singleton cache (through its base class
75  * {@link org.springframework.beans.factory.support.DefaultSingletonBeanRegistry},
76  * singleton/prototype determination, {@link org.springframework.beans.factory.FactoryBean}
77  * handling, aliases, bean definition merging for child bean definitions,
78  * and bean destruction ({@link org.springframework.beans.factory.DisposableBean}
79  * interface, custom destroy methods). Furthermore, it can manage a bean factory
80  * hierarchy (delegating to the parent in case of an unknown bean), through implementing
81  * the {@link org.springframework.beans.factory.HierarchicalBeanFactory} interface.
82  *
83  * <p>The main template methods to be implemented by subclasses are
84  * {@link #getBeanDefinition} and {@link #createBean}, retrieving a bean definition
85  * for a given bean name and creating a bean instance for a given bean definition,
86  * respectively. Default implementations of those operations can be found in
87  * {@link DefaultListableBeanFactory} and {@link AbstractAutowireCapableBeanFactory}.
88  *
89  * @author Rod Johnson
90  * @author Juergen Hoeller
91  * @since 15 April 2001
92  * @see #getBeanDefinition
93  * @see #createBean
94  * @see AbstractAutowireCapableBeanFactory#createBean
95  * @see DefaultListableBeanFactory#getBeanDefinition
96  */

97 public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
98
99     /** Parent bean factory, for bean inheritance support */
100     private BeanFactory parentBeanFactory;
101
102     /** ClassLoader to resolve bean class names with, if necessary */
103     private ClassLoader JavaDoc beanClassLoader = ClassUtils.getDefaultClassLoader();
104
105     /** Whether to cache bean metadata or rather reobtain it for every access */
106     private boolean cacheBeanMetadata = true;
107
108     /** Custom PropertyEditors to apply to the beans of this factory */
109     private final Map JavaDoc customEditors = new HashMap JavaDoc();
110
111     /** Custom PropertyEditorRegistrars to apply to the beans of this factory */
112     private final Set JavaDoc propertyEditorRegistrars = CollectionFactory.createLinkedSetIfPossible(16);
113
114     /** BeanPostProcessors to apply in createBean */
115     private final List JavaDoc beanPostProcessors = new ArrayList JavaDoc();
116
117     /** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */
118     private boolean hasInstantiationAwareBeanPostProcessors;
119
120     /** Indicates whether any DestructionAwareBeanPostProcessors have been registered */
121     private boolean hasDestructionAwareBeanPostProcessors;
122
123     /** Map from scope identifier String to corresponding Scope */
124     private final Map JavaDoc scopes = new HashMap JavaDoc();
125
126     /** Map from alias to canonical bean name */
127     private final Map JavaDoc aliasMap = new HashMap JavaDoc();
128
129     /** Map from ChildBeanDefinition to merged RootBeanDefinition */
130     private final Map JavaDoc mergedBeanDefinitions = CollectionFactory.createIdentityMapIfPossible(16);
131
132     /** Names of beans that have already been created at least once */
133     private final Set JavaDoc alreadyCreated = Collections.synchronizedSet(new HashSet JavaDoc());
134
135     /** Names of beans that are currently in creation */
136     private final ThreadLocal JavaDoc prototypesCurrentlyInCreation = new ThreadLocal JavaDoc();
137
138     /** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
139     private final Map JavaDoc factoryBeanObjectCache = new HashMap JavaDoc();
140
141
142     /**
143      * Create a new AbstractBeanFactory.
144      */

145     public AbstractBeanFactory() {
146     }
147
148     /**
149      * Create a new AbstractBeanFactory with the given parent.
150      * @param parentBeanFactory parent bean factory, or <code>null</code> if none
151      * @see #getBean
152      */

153     public AbstractBeanFactory(BeanFactory parentBeanFactory) {
154         this.parentBeanFactory = parentBeanFactory;
155     }
156
157
158     //---------------------------------------------------------------------
159
// Implementation of BeanFactory interface
160
//---------------------------------------------------------------------
161

162     public Object JavaDoc getBean(String JavaDoc name) throws BeansException {
163         return getBean(name, null, null);
164     }
165         
166     public Object JavaDoc getBean(String JavaDoc name, Class JavaDoc requiredType) throws BeansException {
167         return getBean(name, requiredType, null);
168     }
169
170     /**
171      * Return an instance, which may be shared or independent, of the specified bean.
172      * @param name the name of the bean to retrieve
173      * @param args arguments to use if creating a prototype using explicit arguments to a
174      * static factory method. It is invalid to use a non-null args value in any other case.
175      * @return an instance of the bean
176      * @throws BeansException if the bean could not be created
177      */

178     public Object JavaDoc getBean(String JavaDoc name, Object JavaDoc[] args) throws BeansException {
179         return getBean(name, null, args);
180     }
181
182     /**
183      * Return an instance, which may be shared or independent, of the specified bean.
184      * @param name the name of the bean to retrieve
185      * @param requiredType the required type of the bean to retrieve
186      * @param args arguments to use if creating a prototype using explicit arguments to a
187      * static factory method. It is invalid to use a non-null args value in any other case.
188      * @return an instance of the bean
189      * @throws BeansException if the bean could not be created
190      */

191     public Object JavaDoc getBean(String JavaDoc name, Class JavaDoc requiredType, final Object JavaDoc[] args) throws BeansException {
192         final String JavaDoc beanName = transformedBeanName(name);
193         Object JavaDoc bean = null;
194
195         // Eagerly check singleton cache for manually registered singletons.
196
Object JavaDoc sharedInstance = getSingleton(beanName);
197         if (sharedInstance != null) {
198             if (isSingletonCurrentlyInCreation(beanName)) {
199                 if (logger.isDebugEnabled()) {
200                     logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
201                             "' that is not fully initialized yet - a consequence of a circular reference");
202                 }
203             }
204             else {
205                 if (logger.isDebugEnabled()) {
206                     logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
207                 }
208             }
209             if (containsBeanDefinition(beanName)) {
210                 RootBeanDefinition mbd = getMergedBeanDefinition(beanName, false);
211                 bean = getObjectForBeanInstance(sharedInstance, name, mbd);
212             }
213             else {
214                 bean = getObjectForBeanInstance(sharedInstance, name, null);
215             }
216         }
217
218         else {
219             // Fail if we're already creating this bean instance:
220
// We're assumably within a circular reference.
221
if (isPrototypeCurrentlyInCreation(beanName)) {
222                 throw new BeanCurrentlyInCreationException(beanName);
223             }
224
225             // Check if bean definition exists in this factory.
226
BeanFactory parentBeanFactory = getParentBeanFactory();
227             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
228                 // Not found -> check parent.
229
String JavaDoc nameToLookup = originalBeanName(name);
230                 if (parentBeanFactory instanceof AbstractBeanFactory) {
231                     // Delegation to parent with args only possible for AbstractBeanFactory.
232
return ((AbstractBeanFactory) parentBeanFactory).getBean(nameToLookup, requiredType, args);
233                 }
234                 else if (args == null) {
235                     // No args -> delegate to standard getBean method.
236
return parentBeanFactory.getBean(nameToLookup, requiredType);
237                 }
238                 else {
239                     throw new NoSuchBeanDefinitionException(beanName,
240                             "Cannot delegate to parent BeanFactory because it does not supported passed-in arguments");
241                 }
242             }
243
244             this.alreadyCreated.add(beanName);
245
246             final RootBeanDefinition mbd = getMergedBeanDefinition(beanName, false);
247             checkMergedBeanDefinition(mbd, beanName, args);
248
249             // Create bean instance.
250
if (mbd.isSingleton()) {
251                 sharedInstance = getSingleton(beanName, new ObjectFactory() {
252                     public Object JavaDoc getObject() throws BeansException {
253                         try {
254                             return createBean(beanName, mbd, args);
255                         }
256                         catch (BeansException ex) {
257                             // Explicitly remove instance from singleton cache: It might have been put there
258
// eagerly by the creation process, to allow for circular reference resolution.
259
// Also remove any beans that received a temporary reference to the bean.
260
destroySingleton(beanName);
261                             throw ex;
262                         }
263                     }
264                 });
265                 bean = getObjectForBeanInstance(sharedInstance, name, mbd);
266             }
267
268             else if (mbd.isPrototype()) {
269                 // It's a prototype -> create a new instance.
270
Object JavaDoc prototypeInstance = null;
271                 try {
272                     beforePrototypeCreation(beanName);
273                     prototypeInstance = createBean(beanName, mbd, args);
274                 }
275                 finally {
276                     afterPrototypeCreation(beanName);
277                 }
278                 bean = getObjectForBeanInstance(prototypeInstance, name, mbd);
279             }
280
281             else {
282                 String JavaDoc scopeName = mbd.getScope();
283                 final Scope scope = (Scope) this.scopes.get(scopeName);
284                 if (scope == null) {
285                     throw new IllegalStateException JavaDoc("No Scope registered for scope '" + scopeName + "'");
286                 }
287                 try {
288                     Object JavaDoc scopedInstance = scope.get(beanName, new ObjectFactory() {
289                         public Object JavaDoc getObject() throws BeansException {
290                             beforePrototypeCreation(beanName);
291                             try {
292                                 Object JavaDoc bean = createBean(beanName, mbd, args);
293                                 if (requiresDestruction(bean, mbd)) {
294                                     scope.registerDestructionCallback(beanName,
295                                             new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
296                                 }
297                                 return bean;
298                             }
299                             finally {
300                                 afterPrototypeCreation(beanName);
301                             }
302                         }
303                     });
304                     bean = getObjectForBeanInstance(scopedInstance, name, mbd);
305                 }
306                 catch (IllegalStateException JavaDoc ex) {
307                     throw new BeanCreationException(beanName,
308                             "Scope '" + scopeName + "' is not active for the current thread; " +
309                             "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
310                             ex);
311                 }
312             }
313         }
314
315         // Check if required type matches the type of the actual bean instance.
316
if (requiredType != null && !requiredType.isAssignableFrom(bean.getClass())) {
317             throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
318         }
319         return bean;
320     }
321
322     public boolean containsBean(String JavaDoc name) {
323         if (containsLocalBean(name)) {
324             return true;
325         }
326         // Not found -> check parent.
327
BeanFactory parentBeanFactory = getParentBeanFactory();
328         if (parentBeanFactory != null) {
329             return parentBeanFactory.containsBean(originalBeanName(name));
330         }
331         return false;
332     }
333
334     public boolean isSingleton(String JavaDoc name) throws NoSuchBeanDefinitionException {
335         String JavaDoc beanName = transformedBeanName(name);
336
337         Object JavaDoc beanInstance = getSingleton(beanName);
338         if (beanInstance != null) {
339             if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
340                 return ((FactoryBean) beanInstance).isSingleton();
341             }
342             else {
343                 return true;
344             }
345         }
346
347         else {
348             // No singleton instance found -> check bean definition.
349
BeanFactory parentBeanFactory = getParentBeanFactory();
350             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
351                 // No bean definition found in this factory -> delegate to parent.
352
return parentBeanFactory.isSingleton(originalBeanName(name));
353             }
354
355             RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
356
357             // In case of FactoryBean, return singleton status of created object if not a dereference.
358
if (bd.isSingleton() && !BeanFactoryUtils.isFactoryDereference(name)) {
359                 if (isBeanClassMatch(beanName, bd, FactoryBean.class)) {
360                     FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
361                     return factoryBean.isSingleton();
362                 }
363             }
364
365             return bd.isSingleton();
366         }
367     }
368
369     public boolean isPrototype(String JavaDoc name) throws NoSuchBeanDefinitionException {
370         String JavaDoc beanName = transformedBeanName(name);
371
372         BeanFactory parentBeanFactory = getParentBeanFactory();
373         if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
374             // No bean definition found in this factory -> delegate to parent.
375
return parentBeanFactory.isPrototype(originalBeanName(name));
376         }
377
378         RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
379
380         // In case of FactoryBean, return singleton status of created object if not a dereference.
381
if (bd.isSingleton() && !BeanFactoryUtils.isFactoryDereference(name)) {
382             if (isBeanClassMatch(beanName, bd, FactoryBean.class)) {
383                 FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
384                 return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean).isPrototype()) ||
385                         !factoryBean.isSingleton());
386             }
387         }
388
389         return bd.isPrototype();
390     }
391
392     public boolean isTypeMatch(String JavaDoc name, Class JavaDoc targetType) throws NoSuchBeanDefinitionException {
393         if ((targetType == null || Object JavaDoc.class.equals(targetType)) && containsLocalBean(name)) {
394             return true;
395         }
396
397         String JavaDoc beanName = transformedBeanName(name);
398
399         // Check manually registered singletons.
400
Object JavaDoc beanInstance = getSingleton(beanName);
401         if (beanInstance != null) {
402             if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
403                 Class JavaDoc type = getTypeForFactoryBean((FactoryBean) beanInstance);
404                 return (type != null && targetType.isAssignableFrom(type));
405             }
406             else {
407                 return targetType.isAssignableFrom(beanInstance.getClass());
408             }
409         }
410
411         else {
412             // No singleton instance found -> check bean definition.
413
BeanFactory parentBeanFactory = getParentBeanFactory();
414             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
415                 // No bean definition found in this factory -> delegate to parent.
416
return parentBeanFactory.isTypeMatch(originalBeanName(name), targetType);
417             }
418
419             RootBeanDefinition mbd = getMergedBeanDefinition(beanName, false);
420             Class JavaDoc beanClass = predictBeanType(beanName, mbd);
421
422             if (beanClass == null) {
423                 return false;
424             }
425
426             // Check bean class whether we're dealing with a FactoryBean.
427
if (FactoryBean.class.isAssignableFrom(beanClass) && !BeanFactoryUtils.isFactoryDereference(name)) {
428                 // If it's a FactoryBean, we want to look at what it creates, not the factory class.
429
Class JavaDoc type = getTypeForFactoryBean(beanName, mbd);
430                 return (type != null && targetType.isAssignableFrom(type));
431             }
432             else {
433                 return targetType.isAssignableFrom(beanClass);
434             }
435         }
436     }
437
438     public Class JavaDoc getType(String JavaDoc name) throws NoSuchBeanDefinitionException {
439         String JavaDoc beanName = transformedBeanName(name);
440
441         // Check manually registered singletons.
442
Object JavaDoc beanInstance = getSingleton(beanName);
443         if (beanInstance != null) {
444             if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
445                 return getTypeForFactoryBean((FactoryBean) beanInstance);
446             }
447             else {
448                 return beanInstance.getClass();
449             }
450         }
451
452         else {
453             // No singleton instance found -> check bean definition.
454
BeanFactory parentBeanFactory = getParentBeanFactory();
455             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
456                 // No bean definition found in this factory -> delegate to parent.
457
return parentBeanFactory.getType(originalBeanName(name));
458             }
459
460             RootBeanDefinition mbd = getMergedBeanDefinition(beanName, false);
461             Class JavaDoc beanClass = predictBeanType(beanName, mbd);
462
463             // Check bean class whether we're dealing with a FactoryBean.
464
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass) &&
465                     !BeanFactoryUtils.isFactoryDereference(name)) {
466                 // If it's a FactoryBean, we want to look at what it creates, not the factory class.
467
return getTypeForFactoryBean(beanName, mbd);
468             }
469
470             return beanClass;
471         }
472     }
473
474     public String JavaDoc[] getAliases(String JavaDoc name) {
475         String JavaDoc beanName = transformedBeanName(name);
476         List JavaDoc aliases = new ArrayList JavaDoc();
477         boolean factoryPrefix = name.startsWith(FACTORY_BEAN_PREFIX);
478         String JavaDoc fullBeanName = beanName;
479         if (factoryPrefix) {
480             fullBeanName = FACTORY_BEAN_PREFIX + beanName;
481         }
482         if (!fullBeanName.equals(name)) {
483             aliases.add(fullBeanName);
484         }
485         synchronized (this.aliasMap) {
486             for (Iterator JavaDoc it = this.aliasMap.entrySet().iterator(); it.hasNext();) {
487                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
488                 if (entry.getValue().equals(beanName)) {
489                     String JavaDoc key = (factoryPrefix ? FACTORY_BEAN_PREFIX : "") + entry.getKey();
490                     if (!key.equals(name)) {
491                         aliases.add(key);
492                     }
493                 }
494             }
495         }
496         if (!containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
497             BeanFactory parentBeanFactory = getParentBeanFactory();
498             if (parentBeanFactory != null) {
499                 aliases.addAll(Arrays.asList(parentBeanFactory.getAliases(fullBeanName)));
500             }
501         }
502         return StringUtils.toStringArray(aliases);
503     }
504
505
506     //---------------------------------------------------------------------
507
// Implementation of HierarchicalBeanFactory interface
508
//---------------------------------------------------------------------
509

510     public BeanFactory getParentBeanFactory() {
511         return this.parentBeanFactory;
512     }
513
514     public boolean containsLocalBean(String JavaDoc name) {
515         String JavaDoc beanName = transformedBeanName(name);
516         return (containsSingleton(beanName) || containsBeanDefinition(beanName));
517     }
518
519
520     //---------------------------------------------------------------------
521
// Implementation of ConfigurableBeanFactory interface
522
//---------------------------------------------------------------------
523

524     public void setParentBeanFactory(BeanFactory parentBeanFactory) {
525         if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {
526             throw new IllegalStateException JavaDoc("Already associated with parent BeanFactory: " + this.parentBeanFactory);
527         }
528         this.parentBeanFactory = parentBeanFactory;
529     }
530
531     public void setBeanClassLoader(ClassLoader JavaDoc beanClassLoader) {
532         this.beanClassLoader = (beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader());
533     }
534
535     public ClassLoader JavaDoc getBeanClassLoader() {
536         return this.beanClassLoader;
537     }
538
539     public void setCacheBeanMetadata(boolean cacheBeanMetadata) {
540         this.cacheBeanMetadata = cacheBeanMetadata;
541     }
542
543     public boolean isCacheBeanMetadata() {
544         return this.cacheBeanMetadata;
545     }
546
547     public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) {
548         Assert.notNull(registrar, "PropertyEditorRegistrar must not be null");
549         this.propertyEditorRegistrars.add(registrar);
550     }
551
552     /**
553      * Return the set of PropertyEditorRegistrars.
554      */

555     public Set JavaDoc getPropertyEditorRegistrars() {
556         return this.propertyEditorRegistrars;
557     }
558
559     public void registerCustomEditor(Class JavaDoc requiredType, PropertyEditor JavaDoc propertyEditor) {
560         Assert.notNull(requiredType, "Required type must not be null");
561         Assert.notNull(propertyEditor, "PropertyEditor must not be null");
562         this.customEditors.put(requiredType, propertyEditor);
563     }
564
565     /**
566      * Return the map of custom editors, with Classes as keys
567      * and PropertyEditors as values.
568      */

569     public Map JavaDoc getCustomEditors() {
570         return this.customEditors;
571     }
572
573     public TypeConverter getTypeConverter() {
574         SimpleTypeConverter typeConverter = new SimpleTypeConverter();
575         registerCustomEditors(typeConverter);
576         return typeConverter;
577     }
578
579     public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
580         Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
581         this.beanPostProcessors.add(beanPostProcessor);
582         if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
583             this.hasInstantiationAwareBeanPostProcessors = true;
584         }
585         if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
586             this.hasDestructionAwareBeanPostProcessors = true;
587         }
588     }
589
590     public int getBeanPostProcessorCount() {
591         return this.beanPostProcessors.size();
592     }
593
594     /**
595      * Return the list of BeanPostProcessors that will get applied
596      * to beans created with this factory.
597      */

598     public List JavaDoc getBeanPostProcessors() {
599         return this.beanPostProcessors;
600     }
601
602     /**
603      * Return whether this factory holds a InstantiationAwareBeanPostProcessor
604      * that will get applied to singleton beans on shutdown.
605      * @see #addBeanPostProcessor
606      * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
607      */

608     protected boolean hasInstantiationAwareBeanPostProcessors() {
609         return this.hasInstantiationAwareBeanPostProcessors;
610     }
611
612     /**
613      * Return whether this factory holds a DestructionAwareBeanPostProcessor
614      * that will get applied to singleton beans on shutdown.
615      * @see #addBeanPostProcessor
616      * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
617      */

618     protected boolean hasDestructionAwareBeanPostProcessors() {
619         return this.hasDestructionAwareBeanPostProcessors;
620     }
621
622     public void registerScope(String JavaDoc scopeName, Scope scope) {
623         Assert.notNull(scopeName, "Scope identifier must not be null");
624         Assert.notNull(scope, "Scope must not be null");
625         if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
626             throw new IllegalArgumentException JavaDoc("Cannot replace existing scopes 'singleton' and 'prototype'");
627         }
628         this.scopes.put(scopeName, scope);
629     }
630
631     public String JavaDoc[] getRegisteredScopeNames() {
632         return StringUtils.toStringArray(this.scopes.keySet());
633     }
634
635     public Scope getRegisteredScope(String JavaDoc scopeName) {
636         Assert.notNull(scopeName, "Scope identifier must not be null");
637         return (Scope) this.scopes.get(scopeName);
638     }
639
640     public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
641         Assert.notNull(otherFactory, "BeanFactory must not be null");
642         setBeanClassLoader(otherFactory.getBeanClassLoader());
643         setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
644         if (otherFactory instanceof AbstractBeanFactory) {
645             AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory;
646             this.customEditors.putAll(otherAbstractFactory.customEditors);
647             this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
648             this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors);
649             this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors ||
650                     otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
651             this.hasDestructionAwareBeanPostProcessors = this.hasDestructionAwareBeanPostProcessors ||
652                     otherAbstractFactory.hasDestructionAwareBeanPostProcessors;
653             this.scopes.putAll(otherAbstractFactory.scopes);
654         }
655     }
656
657     public void registerAlias(String JavaDoc beanName, String JavaDoc alias) throws BeanDefinitionStoreException {
658         Assert.hasText(beanName, "'beanName' must not be empty");
659         Assert.hasText(alias, "'alias' must not be empty");
660         if (!alias.equals(beanName)) {
661             // Only actually register the alias if it is not equal to the bean name itself.
662
if (logger.isDebugEnabled()) {
663                 logger.debug("Registering alias '" + alias + "' for bean with name '" + beanName + "'");
664             }
665             synchronized (this.aliasMap) {
666                 Object JavaDoc registeredName = this.aliasMap.get(alias);
667                 if (registeredName != null && !registeredName.equals(beanName)) {
668                     throw new BeanDefinitionStoreException("Cannot register alias '" + alias + "' for bean name '" +
669                             beanName + "': It's already registered for bean name '" + registeredName + "'.");
670                 }
671                 this.aliasMap.put(alias, beanName);
672             }
673         }
674     }
675
676     /**
677      * Callback before prototype creation.
678      * <p>Default implementation register the prototype as currently in creation.
679      * @param beanName the name of the prototype about to be created
680      * @see #isPrototypeCurrentlyInCreation
681      */

682     protected void beforePrototypeCreation(String JavaDoc beanName) {
683         Set JavaDoc beanNames = (Set JavaDoc) this.prototypesCurrentlyInCreation.get();
684         if (beanNames == null) {
685             beanNames = new HashSet JavaDoc();
686             this.prototypesCurrentlyInCreation.set(beanNames);
687         }
688         beanNames.add(beanName);
689     }
690
691     /**
692      * Callback after prototype creation.
693      * <p>Default implementation marks the prototype as not in creation anymore.
694      * @param beanName the name of the prototype that has been created
695      * @see #isPrototypeCurrentlyInCreation
696      */

697     protected void afterPrototypeCreation(String JavaDoc beanName) {
698         Set JavaDoc beanNames = (Set JavaDoc) this.prototypesCurrentlyInCreation.get();
699         if (beanNames != null) {
700             beanNames.remove(beanName);
701             if (beanNames.isEmpty()) {
702                 this.prototypesCurrentlyInCreation.set(null);
703             }
704         }
705     }
706
707     /**
708      * Return whether the specified prototype bean is currently in creation
709      * (within the current thread).
710      * @param beanName the name of the bean
711      */

712     protected final boolean isPrototypeCurrentlyInCreation(String JavaDoc beanName) {
713         Set JavaDoc beanNames = (Set JavaDoc) this.prototypesCurrentlyInCreation.get();
714         return (beanNames != null ? beanNames.contains(beanName) : false);
715     }
716
717     public boolean isCurrentlyInCreation(String JavaDoc beanName) {
718         return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName);
719     }
720
721     public void destroyBean(String JavaDoc beanName, Object JavaDoc beanInstance) {
722         destroyBean(beanName, beanInstance, getMergedBeanDefinition(beanName));
723     }
724
725     /**
726      * Destroy the given bean instance (usually a prototype instance
727      * obtained from this factory) according to the given bean definition.
728      * @param beanName the name of the bean definition
729      * @param beanInstance the bean instance to destroy
730      * @param mbd the merged bean definition
731      */

732     protected void destroyBean(String JavaDoc beanName, Object JavaDoc beanInstance, RootBeanDefinition mbd) {
733         new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors()).destroy();
734     }
735
736     public void destroyScopedBean(String JavaDoc beanName) {
737         RootBeanDefinition mbd = getMergedBeanDefinition(beanName);
738         if (mbd.isSingleton() || mbd.isPrototype()) {
739             throw new IllegalArgumentException JavaDoc(
740                     "Bean name '" + beanName + "' does not correspond to an object in a Scope");
741         }
742         String JavaDoc scopeName = mbd.getScope();
743         Scope scope = (Scope) this.scopes.get(scopeName);
744         if (scope == null) {
745             throw new IllegalStateException JavaDoc("No Scope registered for scope '" + scopeName + "'");
746         }
747         Object JavaDoc bean = scope.remove(beanName);
748         if (bean != null) {
749             destroyBean(beanName, bean, mbd);
750         }
751     }
752
753
754     //---------------------------------------------------------------------
755
// Implementation methods
756
//---------------------------------------------------------------------
757

758     /**
759      * Return the bean name, stripping out the factory dereference prefix if necessary,
760      * and resolving aliases to canonical names.
761      * @param name the user-specified name
762      */

763     protected String JavaDoc transformedBeanName(String JavaDoc name) {
764         String JavaDoc beanName = BeanFactoryUtils.transformedBeanName(name);
765         // Handle aliasing.
766
synchronized (this.aliasMap) {
767             String JavaDoc canonicalName = beanName;
768             String JavaDoc resolvedName = null;
769             do {
770                 resolvedName = (String JavaDoc) this.aliasMap.get(canonicalName);
771                 if (resolvedName != null) {
772                     canonicalName = resolvedName;
773                 }
774             }
775             while (resolvedName != null);
776             return canonicalName;
777         }
778     }
779
780     /**
781      * Determine the original bean name, resolving locally defined aliases to canonical names.
782      * @param name the user-specified name
783      */

784     protected String JavaDoc originalBeanName(String JavaDoc name) {
785         String JavaDoc beanName = transformedBeanName(name);
786         if (name.startsWith(FACTORY_BEAN_PREFIX)) {
787             beanName = FACTORY_BEAN_PREFIX + beanName;
788         }
789         return beanName;
790     }
791
792     /**
793      * Determine whether this given bean name is defines as an alias
794      * (as opposed to the name of an actual bean definition).
795      * @param beanName the bean name to check
796      */

797     protected boolean isAlias(String JavaDoc beanName) {
798         synchronized (this.aliasMap) {
799             return this.aliasMap.containsKey(beanName);
800         }
801     }
802
803     /**
804      * Initialize the given BeanWrapper with the custom editors registered
805      * with this factory. To be called for BeanWrappers that will create
806      * and populate bean instances.
807      * <p>The default implementation delegates to <code>registerCustomEditors</code>.
808      * Can be overridden in subclasses.
809      * @param bw the BeanWrapper to initialize
810      * @see #registerCustomEditors
811      */

812     protected void initBeanWrapper(BeanWrapper bw) {
813         registerCustomEditors(bw);
814     }
815
816     /**
817      * Initialize the given PropertyEditorRegistry with the custom editors
818      * registered with this BeanFactory.
819      * <p>To be called for BeanWrappers that will create and populate bean
820      * instances, and for SimpleTypeConverter used for constructor argument
821      * and factory method type conversion.
822      * @param registry the PropertyEditorRegistry to initialize
823      */

824     protected void registerCustomEditors(PropertyEditorRegistry registry) {
825         registry.registerCustomEditor(String JavaDoc[].class, new StringArrayPropertyEditor());
826         for (Iterator JavaDoc it = this.propertyEditorRegistrars.iterator(); it.hasNext();) {
827             PropertyEditorRegistrar registrar = (PropertyEditorRegistrar) it.next();
828             registrar.registerCustomEditors(registry);
829         }
830         for (Iterator JavaDoc it = this.customEditors.entrySet().iterator(); it.hasNext();) {
831             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
832             Class JavaDoc clazz = (Class JavaDoc) entry.getKey();
833             PropertyEditor JavaDoc editor = (PropertyEditor JavaDoc) entry.getValue();
834             registry.registerCustomEditor(clazz, editor);
835         }
836     }
837
838     /**
839      * Apply the given property values to the given bean.
840      * @param bw the BeanWrapper that wraps the bean
841      * @param pv the PropertyValues to apply
842      */

843     protected void applyPropertyValues(BeanWrapper bw, PropertyValues pv) {
844         // Synchronize if custom editors are registered.
845
// Necessary because PropertyEditors are not thread-safe.
846
if (!this.customEditors.isEmpty()) {
847             synchronized (this.customEditors) {
848                 bw.setPropertyValues(pv);
849             }
850         }
851         else {
852             bw.setPropertyValues(pv);
853         }
854     }
855
856     /**
857      * Convert the given value into the specified target type,
858      * using the specified BeanWrapper.
859      * @param converter the TypeConverter to work on
860      * @param value the original value
861      * @param targetType the target type to convert to
862      * (or <code>null</code> if not known, for example in case of a collection element)
863      * @param methodParam the method parameter that is the target of the conversion
864      * (for analysis of generic types; may be <code>null</code>)
865      * @return the converted value, matching the target type
866      * @throws org.springframework.beans.TypeMismatchException if type conversion failed
867      * @see org.springframework.beans.BeanWrapperImpl#convertIfNecessary(Object, Class)
868      */

869     protected Object JavaDoc doTypeConversionIfNecessary(
870             TypeConverter converter, Object JavaDoc value, Class JavaDoc targetType, MethodParameter methodParam)
871             throws TypeMismatchException {
872
873         // Synchronize if custom editors are registered.
874
// Necessary because PropertyEditors are not thread-safe.
875
if (!this.customEditors.isEmpty()) {
876             synchronized (this.customEditors) {
877                 return converter.convertIfNecessary(value, targetType, methodParam);
878             }
879         }
880         else {
881             return converter.convertIfNecessary(value, targetType, methodParam);
882         }
883     }
884
885
886     /**
887      * Return a RootBeanDefinition for the given bean name,
888      * merging a child bean definition with its parent if necessary.
889      * @param name the name of the bean to retrieve the merged definition for
890      * @return a (potentially merged) RootBeanDefinition for the given bean
891      * @throws NoSuchBeanDefinitionException if there is no bean with the given name
892      * @throws BeanDefinitionStoreException in case of an invalid bean definition
893      */

894     public RootBeanDefinition getMergedBeanDefinition(String JavaDoc name) throws BeansException {
895         return getMergedBeanDefinition(name, false);
896     }
897
898     /**
899      * Return a RootBeanDefinition, even by traversing parent if the parameter is a
900      * child definition. Can ask the parent bean factory if not found in this instance.
901      * @param name the name of the bean to retrieve the merged definition for
902      * @param includingAncestors whether to ask the parent bean factory if not found
903      * in this instance
904      * @return a (potentially merged) RootBeanDefinition for the given bean
905      * @throws NoSuchBeanDefinitionException if there is no bean with the given name
906      * @throws BeanDefinitionStoreException in case of an invalid bean definition
907      */

908     protected RootBeanDefinition getMergedBeanDefinition(String JavaDoc name, boolean includingAncestors)
909         throws BeansException {
910
911         String JavaDoc beanName = transformedBeanName(name);
912
913         // Efficiently check whether bean definition exists in this factory.
914
if (includingAncestors && !containsBeanDefinition(beanName) &&
915                 getParentBeanFactory() instanceof AbstractBeanFactory) {
916             return ((AbstractBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName, true);
917         }
918
919         // Resolve merged bean definition locally.
920
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
921     }
922
923     /**
924      * Return a RootBeanDefinition for the given top-level bean, by merging with
925      * the parent if the given bean's definition is a child bean definition.
926      * @param beanName the name of the bean definition
927      * @param bd the original bean definition (Root/ChildBeanDefinition)
928      * @return a (potentially merged) RootBeanDefinition for the given bean
929      * @throws BeanDefinitionStoreException in case of an invalid bean definition
930      */

931     protected RootBeanDefinition getMergedBeanDefinition(String JavaDoc beanName, BeanDefinition bd)
932             throws BeanDefinitionStoreException {
933
934         return getMergedBeanDefinition(beanName, bd, null);
935     }
936
937     /**
938      * Return a RootBeanDefinition for the given bean, by merging with the
939      * parent if the given bean's definition is a child bean definition.
940      * @param beanName the name of the bean definition
941      * @param bd the original bean definition (Root/ChildBeanDefinition)
942      * @param containingBd the containing bean definition in case of inner bean,
943      * or <code>null</code> in case of a top-level bean
944      * @return a (potentially merged) RootBeanDefinition for the given bean
945      * @throws BeanDefinitionStoreException in case of an invalid bean definition
946      */

947     protected RootBeanDefinition getMergedBeanDefinition(
948             String JavaDoc beanName, BeanDefinition bd, BeanDefinition containingBd)
949             throws BeanDefinitionStoreException {
950
951         synchronized (this.mergedBeanDefinitions) {
952             RootBeanDefinition mbd = (RootBeanDefinition) this.mergedBeanDefinitions.get(bd);
953             if (mbd == null) {
954
955                 if (bd instanceof RootBeanDefinition) {
956                     // Use copy of given root bean definition.
957
mbd = new RootBeanDefinition((RootBeanDefinition) bd);
958                 }
959
960                 else if (bd instanceof ChildBeanDefinition) {
961                     // Child bean definition: needs to be merged with parent.
962
ChildBeanDefinition cbd = (ChildBeanDefinition) bd;
963                     RootBeanDefinition pbd = null;
964                     try {
965                         if (!beanName.equals(cbd.getParentName())) {
966                             pbd = getMergedBeanDefinition(cbd.getParentName(), true);
967                         }
968                         else {
969                             if (getParentBeanFactory() instanceof AbstractBeanFactory) {
970                                 AbstractBeanFactory parentFactory = (AbstractBeanFactory) getParentBeanFactory();
971                                 pbd = parentFactory.getMergedBeanDefinition(cbd.getParentName(), true);
972                             }
973                             else {
974                                 throw new NoSuchBeanDefinitionException(cbd.getParentName(),
975                                         "Parent name '" + cbd.getParentName() + "' is equal to bean name '" + beanName +
976                                         "': cannot be resolved without an AbstractBeanFactory parent");
977                             }
978                         }
979                     }
980                     catch (NoSuchBeanDefinitionException ex) {
981                         throw new BeanDefinitionStoreException(cbd.getResourceDescription(), beanName,
982                                 "Could not resolve parent bean definition '" + cbd.getParentName() + "'", ex);
983                     }
984
985                     // Deep copy with overridden values.
986
mbd = new RootBeanDefinition(pbd);
987                     mbd.overrideFrom(cbd);
988                 }
989
990                 else {
991                     throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
992                             "Definition is neither a RootBeanDefinition nor a ChildBeanDefinition: " + bd);
993                 }
994
995                 // A bean contained in a non-singleton bean cannot be a singleton itself.
996
// Let's correct this on the fly here, since this might be the result of
997
// parent-child merging for the outer bean, in which case the original inner bean
998
// definition will not have inherited the merged outer bean's singleton status.
999
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
1000                    mbd.setSingleton(false);
1001                }
1002
1003                // Only cache the merged bean definition if we're already about to create an
1004
// instance of the bean, or at least have already created an instance before.
1005
if (containingBd == null && isCacheBeanMetadata() && this.alreadyCreated.contains(beanName)) {
1006                    this.mergedBeanDefinitions.put(bd, mbd);
1007                }
1008            }
1009
1010            return mbd;
1011        }
1012    }
1013
1014    /**
1015     * Check the given merged bean definition,
1016     * potentially throwing validation exceptions.
1017     * @param mbd the merged bean definition to check
1018     * @param beanName the name of the bean
1019     * @param args the arguments for bean creation, if any
1020     * @throws BeanDefinitionStoreException in case of validation failure
1021     */

1022    protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String JavaDoc beanName, Object JavaDoc[] args)
1023            throws BeanDefinitionStoreException {
1024
1025        // check if bean definition is not abstract
1026
if (mbd.isAbstract()) {
1027            throw new BeanIsAbstractException(beanName);
1028        }
1029
1030        // Check validity of the usage of the args parameter. This can
1031
// only be used for prototypes constructed via a factory method.
1032
if (args != null) {
1033            if (mbd.isSingleton()) {
1034                throw new BeanDefinitionStoreException(
1035                        "Cannot specify arguments in the getBean() method when referring to a singleton bean definition");
1036            }
1037            else if (mbd.getFactoryMethodName() == null) {
1038                throw new BeanDefinitionStoreException(
1039                        "Can only specify arguments in the getBean() method in conjunction with a factory method");
1040            }
1041        }
1042    }
1043
1044    /**
1045     * Resolve the bean class for the specified bean definition,
1046     * resolving a bean class name into a Class reference (if necessary)
1047     * and storing the resolved Class in the bean definition for further use.
1048     * @param mbd the merged bean definition to determine the class for
1049     * @param beanName the name of the bean (for error handling purposes)
1050     * @return the resolved bean class (or <code>null</code> if none)
1051     * @throws CannotLoadBeanClassException if we failed to load the class
1052     */

1053    protected Class JavaDoc resolveBeanClass(RootBeanDefinition mbd, String JavaDoc beanName) throws CannotLoadBeanClassException {
1054        if (mbd.hasBeanClass()) {
1055            return mbd.getBeanClass();
1056        }
1057        try {
1058            return mbd.resolveBeanClass(getBeanClassLoader());
1059        }
1060        catch (ClassNotFoundException JavaDoc ex) {
1061            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
1062        }
1063        catch (LinkageError JavaDoc err) {
1064            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
1065        }
1066    }
1067
1068
1069    /**
1070     * Check whether the bean class of the given bean definition matches
1071     * the specified target type. Allows for lazy loading of the actual
1072     * bean class, provided that the type match can be determined otherwise.
1073     * <p>The default implementation simply delegates to the standard
1074     * <code>resolveBeanClass</code> method. Subclasses may override this
1075     * to use a different strategy, such as a throwaway class loaer.
1076     * @param beanName the name of the bean (for error handling purposes)
1077     * @param mbd the merged bean definition to determine the class for
1078     * @param targetType the type to match against (never <code>null</code>)
1079     * @return the resolved bean class (or <code>null</code> if none)
1080     * @throws CannotLoadBeanClassException if we failed to load the class
1081     * @see #resolveBeanClass
1082     */

1083    protected boolean isBeanClassMatch(String JavaDoc beanName, RootBeanDefinition mbd, Class JavaDoc targetType)
1084            throws CannotLoadBeanClassException {
1085
1086        Class JavaDoc beanClass = resolveBeanClass(mbd, beanName);
1087        return (beanClass != null && targetType.isAssignableFrom(beanClass));
1088    }
1089
1090    /**
1091     * Predict the eventual bean type (of the processed bean instance) for the
1092     * specified bean. Called by {@link #getType} and {@link #isTypeMatch}.
1093     * Does not need to handle FactoryBeans specifically, since it is only
1094     * supposed to operate on the raw bean type.
1095     * <p>This implementation is simplistic in that it is not able to
1096     * handle factory methods and InstantiationAwareBeanPostProcessors.
1097     * It only predicts the bean type correctly for a standard bean.
1098     * To be overridden in subclasses, applying more sophisticated type detection.
1099     * @param beanName the name of the bean
1100     * @param mbd the merged bean definition to determine the type for
1101     * @return the type of the bean, or <code>null</code> if not predictable
1102     */

1103    protected Class JavaDoc predictBeanType(String JavaDoc beanName, RootBeanDefinition mbd) {
1104        if (mbd.getFactoryMethodName() == null) {
1105            return resolveBeanClass(mbd, beanName);
1106        }
1107        return null;
1108    }
1109
1110    /**
1111     * Determine the bean type for the given FactoryBean definition, as far as possible.
1112     * Only called if there is no singleton instance registered for the target bean already.
1113     * <p>Default implementation creates the FactoryBean via <code>getBean</code>
1114     * to call its <code>getObjectType</code> method. Subclasses are encouraged to optimize
1115     * this, typically by just instantiating the FactoryBean but not populating it yet,
1116     * trying whether its <code>getObjectType</code> method already returns a type.
1117     * If no type found, a full FactoryBean creation as performed by this implementation
1118     * should be used as fallback.
1119     * @param beanName the name of the bean
1120     * @param mbd the merged bean definition for the bean
1121     * @return the type for the bean if determinable, or <code>null</code> else
1122     * @see org.springframework.beans.factory.FactoryBean#getObjectType()
1123     * @see #getBean(String)
1124     */

1125    protected Class JavaDoc getTypeForFactoryBean(String JavaDoc beanName, RootBeanDefinition mbd) {
1126        try {
1127            FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
1128            return getTypeForFactoryBean(factoryBean);
1129        }
1130        catch (BeanCreationException ex) {
1131            // Can only happen when getting a FactoryBean.
1132
logger.debug("Ignoring bean creation exception on FactoryBean type check", ex);
1133            return null;
1134        }
1135    }
1136
1137    /**
1138     * Determine the type for the given FactoryBean.
1139     * @param factoryBean the FactoryBean instance to check
1140     * @return the FactoryBean's object type,
1141     * or <code>null</code> if the type cannot be determined yet
1142     */

1143    protected Class JavaDoc getTypeForFactoryBean(FactoryBean factoryBean) {
1144        try {
1145            return factoryBean.getObjectType();
1146        }
1147        catch (Throwable JavaDoc ex) {
1148            // Thrown from the FactoryBean's getObjectType implementation.
1149
logger.warn("FactoryBean threw exception from getObjectType, despite the contract saying " +
1150                    "that it should return null if the type of its object cannot be determined yet", ex);
1151            return null;
1152        }
1153    }
1154
1155
1156    /**
1157     * Get the object for the given bean instance, either the bean
1158     * instance itself or its created object in case of a FactoryBean.
1159     * @param beanInstance the shared bean instance
1160     * @param name name that may include factory dereference prefix
1161     * @param mbd the merged bean definition
1162     * @return the object to expose for the bean
1163     */

1164    protected Object JavaDoc getObjectForBeanInstance(Object JavaDoc beanInstance, String JavaDoc name, RootBeanDefinition mbd) {
1165        String JavaDoc beanName = transformedBeanName(name);
1166
1167        // Don't let calling code try to dereference the
1168
// bean factory if the bean isn't a factory.
1169
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
1170            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
1171        }
1172
1173        boolean shared = (mbd == null || mbd.isSingleton());
1174        Object JavaDoc object = beanInstance;
1175
1176        // Now we have the bean instance, which may be a normal bean or a FactoryBean.
1177
// If it's a FactoryBean, we use it to create a bean instance, unless the
1178
// caller actually wants a reference to the factory.
1179
if (beanInstance instanceof FactoryBean) {
1180            if (!BeanFactoryUtils.isFactoryDereference(name)) {
1181                // Return bean instance from factory.
1182
FactoryBean factory = (FactoryBean) beanInstance;
1183                if (logger.isTraceEnabled()) {
1184                    logger.trace("Bean with name '" + beanName + "' is a factory bean");
1185                }
1186                // Cache object obtained from FactoryBean if it is a singleton.
1187
if (shared && factory.isSingleton()) {
1188                    synchronized (getSingletonMutex()) {
1189                        object = this.factoryBeanObjectCache.get(beanName);
1190                        if (object == null) {
1191                            object = getObjectFromFactoryBean(factory, beanName, mbd);
1192                            this.factoryBeanObjectCache.put(beanName, object);
1193                        }
1194                    }
1195                }
1196                else {
1197                    object = getObjectFromFactoryBean(factory, beanName, mbd);
1198                }
1199            }
1200            else {
1201                // The user wants the factory itself.
1202
if (logger.isTraceEnabled()) {
1203                    logger.trace("Calling code asked for FactoryBean instance for name '" + beanName + "'");
1204                }
1205            }
1206        }
1207
1208        return object;
1209    }
1210
1211    /**
1212     * Obtain an object to expose from the given FactoryBean.
1213     * @param factory the FactoryBean instance
1214     * @param beanName the name of the bean
1215     * @param mbd the merged bean definition
1216     * @return the object obtained from the FactoryBean
1217     * @throws BeanCreationException if FactoryBean object creation failed
1218     * @see org.springframework.beans.factory.FactoryBean#getObject()
1219     */

1220    private Object JavaDoc getObjectFromFactoryBean(FactoryBean factory, String JavaDoc beanName, RootBeanDefinition mbd)
1221            throws BeanCreationException {
1222
1223        Object JavaDoc object;
1224
1225        try {
1226            object = factory.getObject();
1227        }
1228        catch (FactoryBeanNotInitializedException ex) {
1229            throw new BeanCurrentlyInCreationException(beanName, ex.toString());
1230        }
1231        catch (Throwable JavaDoc ex) {
1232            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
1233        }
1234
1235        // Do not accept a null value for a FactoryBean that's not fully
1236
// initialized yet: Many FactoryBeans just return null then.
1237
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
1238            throw new BeanCurrentlyInCreationException(
1239                    beanName, "FactoryBean which is currently in creation returned null from getObject");
1240        }
1241
1242        if (object != null && (mbd == null || !mbd.isSynthetic())) {
1243            try {
1244                object = postProcessObjectFromFactoryBean(object, beanName);
1245            }
1246            catch (Throwable JavaDoc ex) {
1247                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
1248                        "Post-processing of the FactoryBean's object failed", ex);
1249            }
1250        }
1251
1252        return object;
1253    }
1254
1255    /**
1256     * Post-process the given object that has been obtained from the FactoryBean.
1257     * The resulting object will get exposed for bean references.
1258     * <p>The default implementation simply returns the given object as-is.
1259     * Subclasses may override this, for example, to apply post-processors.
1260     * @param object the object obtained from the FactoryBean.
1261     * @param beanName the name of the bean
1262     * @return the object to expose
1263     * @throws BeansException if any post-processing failed
1264     */

1265    protected Object JavaDoc postProcessObjectFromFactoryBean(Object JavaDoc object, String JavaDoc beanName) throws BeansException {
1266        return object;
1267    }
1268
1269    /**
1270     * Determine whether the bean with the given name is a FactoryBean.
1271     * @param name the name of the bean to check
1272     * @return whether the bean is a FactoryBean
1273     * (<code>false</code> means the bean exists but is not a FactoryBean)
1274     * @throws NoSuchBeanDefinitionException if there is no bean with the given name
1275     */

1276    public boolean isFactoryBean(String JavaDoc name) throws NoSuchBeanDefinitionException {
1277        String JavaDoc beanName = transformedBeanName(name);
1278
1279        Object JavaDoc beanInstance = getSingleton(beanName);
1280        if (beanInstance != null) {
1281            return (beanInstance instanceof FactoryBean);
1282        }
1283
1284        // No singleton instance found -> check bean definition.
1285
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof AbstractBeanFactory) {
1286            // No bean definition found in this factory -> delegate to parent.
1287
return ((AbstractBeanFactory) getParentBeanFactory()).isFactoryBean(name);
1288        }
1289
1290        RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
1291        return isBeanClassMatch(beanName, bd, FactoryBean.class);
1292    }
1293
1294
1295    /**
1296     * Determine whether the given bean name is already in use within this factory,
1297     * that is, whether there is a local bean registered under this name or
1298     * an inner bean created with this name.
1299     * @param beanName the name to check
1300     */

1301    protected boolean isBeanNameInUse(String JavaDoc beanName) {
1302        return containsLocalBean(beanName) || hasDependentBean(beanName);
1303    }
1304
1305    /**
1306     * Determine whether the given bean requires destruction on shutdown.
1307     * <p>The default implementation checks the DisposableBean interface as well as
1308     * a specified destroy method and registered DestructionAwareBeanPostProcessors.
1309     * @param bean the bean instance to check
1310     * @param mbd the corresponding bean definition
1311     * @see org.springframework.beans.factory.DisposableBean
1312     * @see AbstractBeanDefinition#getDestroyMethodName()
1313     * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
1314     */

1315    protected boolean requiresDestruction(Object JavaDoc bean, RootBeanDefinition mbd) {
1316        return (bean instanceof DisposableBean || mbd.getDestroyMethodName() != null ||
1317                hasDestructionAwareBeanPostProcessors());
1318    }
1319
1320    /**
1321     * Add the given bean to the list of disposable beans in this factory,
1322     * registering its DisposableBean interface and/or the given destroy method
1323     * to be called on factory shutdown (if applicable). Only applies to singletons.
1324     * <p>Also registers bean as dependent on other beans, according to the
1325     * "depends-on" configuration in the bean definition.
1326     * @param beanName the name of the bean
1327     * @param bean the bean instance
1328     * @param mbd the bean definition for the bean
1329     * @see RootBeanDefinition#isSingleton
1330     * @see RootBeanDefinition#getDependsOn
1331     * @see #registerDisposableBean
1332     * @see #registerDependentBean
1333     */

1334    protected void registerDisposableBeanIfNecessary(String JavaDoc beanName, Object JavaDoc bean, RootBeanDefinition mbd) {
1335        if (mbd.isSingleton() && requiresDestruction(bean, mbd)) {
1336            // Register a DisposableBean implementation that performs all destruction
1337
// work for the given bean: DestructionAwareBeanPostProcessors,
1338
// DisposableBean interface, custom destroy method.
1339
registerDisposableBean(beanName,
1340                    new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
1341
1342            // Register bean as dependent on other beans, if necessary,
1343
// for correct shutdown order.
1344
String JavaDoc[] dependsOn = mbd.getDependsOn();
1345            if (dependsOn != null) {
1346                for (int i = 0; i < dependsOn.length; i++) {
1347                    registerDependentBean(dependsOn[i], beanName);
1348                }
1349            }
1350        }
1351    }
1352
1353    /**
1354     * Overridden to clear the FactoryBean object cache as well.
1355     */

1356    protected void removeSingleton(String JavaDoc beanName) {
1357        super.removeSingleton(beanName);
1358        this.factoryBeanObjectCache.remove(beanName);
1359    }
1360
1361
1362    //---------------------------------------------------------------------
1363
// Abstract methods to be implemented by subclasses
1364
//---------------------------------------------------------------------
1365

1366    /**
1367     * Check if this bean factory contains a bean definition with the given name.
1368     * Does not consider any hierarchy this factory may participate in.
1369     * Invoked by <code>containsBean</code> when no cached singleton instance is found.
1370     * <p>Depending on the nature of the concrete bean factory implementation,
1371     * this operation might be expensive (for example, because of directory lookups
1372     * in external registries). However, for listable bean factories, this usually
1373     * just amounts to a local hash lookup: The operation is therefore part of the
1374     * public interface there. The same implementation can serve for both this
1375     * template method and the public interface method in that case.
1376     * @param beanName the name of the bean to look for
1377     * @return if this bean factory contains a bean definition with the given name
1378     * @see #containsBean
1379     * @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition
1380     */

1381    protected abstract boolean containsBeanDefinition(String JavaDoc beanName);
1382
1383    /**
1384     * Return the bean definition for the given bean name.
1385     * Subclasses should normally implement caching, as this method is invoked
1386     * by this class every time bean definition metadata is needed.
1387     * <p>Depending on the nature of the concrete bean factory implementation,
1388     * this operation might be expensive (for example, because of directory lookups
1389     * in external registries). However, for listable bean factories, this usually
1390     * just amounts to a local hash lookup: The operation is therefore part of the
1391     * public interface there. The same implementation can serve for both this
1392     * template method and the public interface method in that case.
1393     * @param beanName the name of the bean to find a definition for
1394     * @return the BeanDefinition for this prototype name (never <code>null</code>)
1395     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
1396     * if the bean definition cannot be resolved
1397     * @throws BeansException in case of errors
1398     * @see RootBeanDefinition
1399     * @see ChildBeanDefinition
1400     * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
1401     */

1402    protected abstract BeanDefinition getBeanDefinition(String JavaDoc beanName) throws BeansException;
1403
1404    /**
1405     * Create a bean instance for the given bean definition.
1406     * The bean definition will already have been merged with the parent
1407     * definition in case of a child definition.
1408     * <p>All the other methods in this class invoke this method, although
1409     * beans may be cached after being instantiated by this method. All bean
1410     * instantiation within this class is performed by this method.
1411     * @param beanName the name of the bean
1412     * @param mbd the merged bean definition for the bean
1413     * @param args arguments to use if creating a prototype using explicit arguments to a
1414     * static factory method. This parameter must be <code>null</code> except in this case.
1415     * @return a new instance of the bean
1416     * @throws BeanCreationException if the bean could not be created
1417     */

1418    protected abstract Object JavaDoc createBean(String JavaDoc beanName, RootBeanDefinition mbd, Object JavaDoc[] args)
1419            throws BeanCreationException;
1420
1421}
1422
Popular Tags