1 /*
2 * Copyright 2002-2008 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.beans.factory.support;
18
19 import java.beans.PropertyEditor;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.springframework.beans.BeanUtils;
32 import org.springframework.beans.BeanWrapper;
33 import org.springframework.beans.BeansException;
34 import org.springframework.beans.PropertyEditorRegistrar;
35 import org.springframework.beans.PropertyEditorRegistry;
36 import org.springframework.beans.PropertyEditorRegistrySupport;
37 import org.springframework.beans.SimpleTypeConverter;
38 import org.springframework.beans.TypeConverter;
39 import org.springframework.beans.factory.BeanCreationException;
40 import org.springframework.beans.factory.BeanCurrentlyInCreationException;
41 import org.springframework.beans.factory.BeanDefinitionStoreException;
42 import org.springframework.beans.factory.BeanFactory;
43 import org.springframework.beans.factory.BeanFactoryUtils;
44 import org.springframework.beans.factory.BeanIsAbstractException;
45 import org.springframework.beans.factory.BeanIsNotAFactoryException;
46 import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
47 import org.springframework.beans.factory.CannotLoadBeanClassException;
48 import org.springframework.beans.factory.DisposableBean;
49 import org.springframework.beans.factory.FactoryBean;
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.core.CollectionFactory;
60 import org.springframework.core.DecoratingClassLoader;
61 import org.springframework.core.NamedThreadLocal;
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 FactoryBeanRegistrySupport 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 beanClassLoader = ClassUtils.getDefaultClassLoader();
104
105 /** ClassLoader to temporarily resolve bean class names with, if necessary */
106 private ClassLoader tempClassLoader;
107
108 /** Whether to cache bean metadata or rather reobtain it for every access */
109 private boolean cacheBeanMetadata = true;
110
111 /** Custom PropertyEditorRegistrars to apply to the beans of this factory */
112 private final Set propertyEditorRegistrars = new LinkedHashSet(4);
113
114 /** Custom PropertyEditors to apply to the beans of this factory */
115 private final Map customEditors = new HashMap(4);
116
117 /** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
118 private TypeConverter typeConverter;
119
120 /** BeanPostProcessors to apply in createBean */
121 private final List beanPostProcessors = new ArrayList();
122
123 /** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */
124 private boolean hasInstantiationAwareBeanPostProcessors;
125
126 /** Indicates whether any DestructionAwareBeanPostProcessors have been registered */
127 private boolean hasDestructionAwareBeanPostProcessors;
128
129 /** Map from scope identifier String to corresponding Scope */
130 private final Map scopes = new HashMap();
131
132 /** Map from bean name to merged RootBeanDefinition */
133 private final Map mergedBeanDefinitions = CollectionFactory.createConcurrentMapIfPossible(16);
134
135 /** Names of beans that have already been created at least once */
136 private final Set alreadyCreated = Collections.synchronizedSet(new HashSet());
137
138 /** Names of beans that are currently in creation */
139 private final ThreadLocal prototypesCurrentlyInCreation =
140 new NamedThreadLocal("Prototype beans currently in creation");
141
142
143 /**
144 * Create a new AbstractBeanFactory.
145 */
146 public AbstractBeanFactory() {
147 }
148
149 /**
150 * Create a new AbstractBeanFactory with the given parent.
151 * @param parentBeanFactory parent bean factory, or <code>null</code> if none
152 * @see #getBean
153 */
154 public AbstractBeanFactory(BeanFactory parentBeanFactory) {
155 this.parentBeanFactory = parentBeanFactory;
156 }
157
158
159 //---------------------------------------------------------------------
160 // Implementation of BeanFactory interface
161 //---------------------------------------------------------------------
162
163 public Object getBean(String name) throws BeansException {
164 return getBean(name, null, null);
165 }
166
167 public Object getBean(String name, Class requiredType) throws BeansException {
168 return getBean(name, requiredType, null);
169 }
170
171 public Object getBean(String name, Object[] args) throws BeansException {
172 return getBean(name, null, args);
173 }
174
175 /**
176 * Return an instance, which may be shared or independent, of the specified bean.
177 * @param name the name of the bean to retrieve
178 * @param requiredType the required type of the bean to retrieve
179 * @param args arguments to use if creating a prototype using explicit arguments to a
180 * static factory method. It is invalid to use a non-null args value in any other case.
181 * @return an instance of the bean
182 * @throws BeansException if the bean could not be created
183 */
184 public Object getBean(String name, Class requiredType, Object[] args) throws BeansException {
185 return doGetBean(name, requiredType, args, false);
186 }
187
188 /**
189 * Return an instance, which may be shared or independent, of the specified bean.
190 * @param name the name of the bean to retrieve
191 * @param requiredType the required type of the bean to retrieve
192 * @param args arguments to use if creating a prototype using explicit arguments to a
193 * static factory method. It is invalid to use a non-null args value in any other case.
194 * @param typeCheckOnly whether the instance is obtained for a type check,
195 * not for actual use
196 * @return an instance of the bean
197 * @throws BeansException if the bean could not be created
198 */
199 protected Object doGetBean(
200 final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
201
202 final String beanName = transformedBeanName(name);
203 Object bean = null;
204
205 // Eagerly check singleton cache for manually registered singletons.
206 Object sharedInstance = getSingleton(beanName);
207 if (sharedInstance != null) {
208 if (logger.isDebugEnabled()) {
209 if (isSingletonCurrentlyInCreation(beanName)) {
210 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
211 "' that is not fully initialized yet - a consequence of a circular reference");
212 }
213 else {
214 logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
215 }
216 }
217 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
218 }
219
220 else {
221 // Fail if we're already creating this bean instance:
222 // We're assumably within a circular reference.
223 if (isPrototypeCurrentlyInCreation(beanName)) {
224 throw new BeanCurrentlyInCreationException(beanName);
225 }
226
227 // Check if bean definition exists in this factory.
228 BeanFactory parentBeanFactory = getParentBeanFactory();
229 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
230 // Not found -> check parent.
231 String nameToLookup = originalBeanName(name);
232 if (args != null) {
233 // Delegation to parent with explicit args.
234 return parentBeanFactory.getBean(nameToLookup, args);
235 }
236 else {
237 // No args -> delegate to standard getBean method.
238 return parentBeanFactory.getBean(nameToLookup, requiredType);
239 }
240 }
241
242 if (!typeCheckOnly) {
243 markBeanAsCreated(beanName);
244 }
245
246 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
247 checkMergedBeanDefinition(mbd, beanName, args);
248
249 // Guarantee initialization of beans that the current bean depends on.
250 String[] dependsOn = mbd.getDependsOn();
251 if (dependsOn != null) {
252 for (int i = 0; i < dependsOn.length; i++) {
253 String dependsOnBean = dependsOn[i];
254 getBean(dependsOnBean);
255 registerDependentBean(dependsOnBean, beanName);
256 }
257 }
258
259 // Create bean instance.
260 if (mbd.isSingleton()) {
261 sharedInstance = getSingleton(beanName, new ObjectFactory() {
262 public Object getObject() throws BeansException {
263 try {
264 return createBean(beanName, mbd, args);
265 }
266 catch (BeansException ex) {
267 // Explicitly remove instance from singleton cache: It might have been put there
268 // eagerly by the creation process, to allow for circular reference resolution.
269 // Also remove any beans that received a temporary reference to the bean.
270 destroySingleton(beanName);
271 throw ex;
272 }
273 }
274 });
275 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
276 }
277
278 else if (mbd.isPrototype()) {
279 // It's a prototype -> create a new instance.
280 Object prototypeInstance = null;
281 try {
282 beforePrototypeCreation(beanName);
283 prototypeInstance = createBean(beanName, mbd, args);
284 }
285 finally {
286 afterPrototypeCreation(beanName);
287 }
288 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
289 }
290
291 else {
292 String scopeName = mbd.getScope();
293 final Scope scope = (Scope) this.scopes.get(scopeName);
294 if (scope == null) {
295 throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
296 }
297 try {
298 Object scopedInstance = scope.get(beanName, new ObjectFactory() {
299 public Object getObject() throws BeansException {
300 beforePrototypeCreation(beanName);
301 try {
302 return createBean(beanName, mbd, args);
303 }
304 finally {
305 afterPrototypeCreation(beanName);
306 }
307 }
308 });
309 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
310 }
311 catch (IllegalStateException ex) {
312 throw new BeanCreationException(beanName,
313 "Scope '" + scopeName + "' is not active for the current thread; " +
314 "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
315 ex);
316 }
317 }
318 }
319
320 // Check if required type matches the type of the actual bean instance.
321 if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
322 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
323 }
324 return bean;
325 }
326
327 public boolean containsBean(String name) {
328 String beanName = transformedBeanName(name);
329 if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
330 return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
331 }
332 // Not found -> check parent.
333 BeanFactory parentBeanFactory = getParentBeanFactory();
334 return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
335 }
336
337 public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
338 String beanName = transformedBeanName(name);
339
340 Object beanInstance = getSingleton(beanName, false);
341 if (beanInstance != null) {
342 if (beanInstance instanceof FactoryBean) {
343 return (BeanFactoryUtils.isFactoryDereference(name) || ((FactoryBean) beanInstance).isSingleton());
344 }
345 else {
346 return !BeanFactoryUtils.isFactoryDereference(name);
347 }
348 }
349
350 else {
351 // No singleton instance found -> check bean definition.
352 BeanFactory parentBeanFactory = getParentBeanFactory();
353 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
354 // No bean definition found in this factory -> delegate to parent.
355 return parentBeanFactory.isSingleton(originalBeanName(name));
356 }
357
358 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
359
360 // In case of FactoryBean, return singleton status of created object if not a dereference.
361 if (mbd.isSingleton()) {
362 if (isFactoryBean(beanName, mbd)) {
363 if (BeanFactoryUtils.isFactoryDereference(name)) {
364 return true;
365 }
366 FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
367 return factoryBean.isSingleton();
368 }
369 else {
370 return !BeanFactoryUtils.isFactoryDereference(name);
371 }
372 }
373 else {
374 return false;
375 }
376 }
377 }
378
379 public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
380 String beanName = transformedBeanName(name);
381
382 BeanFactory parentBeanFactory = getParentBeanFactory();
383 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
384 // No bean definition found in this factory -> delegate to parent.
385 return parentBeanFactory.isPrototype(originalBeanName(name));
386 }
387
388 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
389 if (mbd.isPrototype()) {
390 // In case of FactoryBean, return singleton status of created object if not a dereference.
391 return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd));
392 }
393 else {
394 // Singleton or scoped - not a prototype.
395 // However, FactoryBean may still produce a prototype object...
396 if (BeanFactoryUtils.isFactoryDereference(name)) {
397 return false;
398 }
399 if (isFactoryBean(beanName, mbd)) {
400 FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
401 return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean).isPrototype()) ||
402 !factoryBean.isSingleton());
403 }
404 else {
405 return false;
406 }
407 }
408 }
409
410 public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
411 String beanName = transformedBeanName(name);
412 Class typeToMatch = (targetType != null ? targetType : Object.class);
413
414 // Check manually registered singletons.
415 Object beanInstance = getSingleton(beanName, false);
416 if (beanInstance != null) {
417 if (beanInstance instanceof FactoryBean) {
418 if (!BeanFactoryUtils.isFactoryDereference(name)) {
419 Class type = getTypeForFactoryBean((FactoryBean) beanInstance);
420 return (type != null && typeToMatch.isAssignableFrom(type));
421 }
422 else {
423 return typeToMatch.isAssignableFrom(beanInstance.getClass()) ;
424 }
425 }
426 else {
427 return !BeanFactoryUtils.isFactoryDereference(name) &&
428 typeToMatch.isAssignableFrom(beanInstance.getClass());
429 }
430 }
431
432 else {
433 // No singleton instance found -> check bean definition.
434 BeanFactory parentBeanFactory = getParentBeanFactory();
435 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
436 // No bean definition found in this factory -> delegate to parent.
437 return parentBeanFactory.isTypeMatch(originalBeanName(name), targetType);
438 }
439
440 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
441 Class beanClass = predictBeanType(beanName, mbd, new Class[] {FactoryBean.class, typeToMatch});
442 if (beanClass == null) {
443 return false;
444 }
445
446 // Check bean class whether we're dealing with a FactoryBean.
447 if (FactoryBean.class.isAssignableFrom(beanClass)) {
448 if (!BeanFactoryUtils.isFactoryDereference(name)) {
449 // If it's a FactoryBean, we want to look at what it creates, not the factory class.
450 Class type = getTypeForFactoryBean(beanName, mbd);
451 return (type != null && typeToMatch.isAssignableFrom(type));
452 }
453 else {
454 return typeToMatch.isAssignableFrom(beanClass);
455 }
456 }
457 else {
458 return !BeanFactoryUtils.isFactoryDereference(name) &&
459 typeToMatch.isAssignableFrom(beanClass);
460 }
461 }
462 }
463
464 public Class getType(String name) throws NoSuchBeanDefinitionException {
465 String beanName = transformedBeanName(name);
466
467 // Check manually registered singletons.
468 Object beanInstance = getSingleton(beanName, false);
469 if (beanInstance != null) {
470 if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
471 return getTypeForFactoryBean((FactoryBean) beanInstance);
472 }
473 else {
474 return beanInstance.getClass();
475 }
476 }
477
478 else {
479 // No singleton instance found -> check bean definition.
480 BeanFactory parentBeanFactory = getParentBeanFactory();
481 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
482 // No bean definition found in this factory -> delegate to parent.
483 return parentBeanFactory.getType(originalBeanName(name));
484 }
485
486 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
487 Class beanClass = predictBeanType(beanName, mbd, null);
488
489 // Check bean class whether we're dealing with a FactoryBean.
490 if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
491 if (!BeanFactoryUtils.isFactoryDereference(name)) {
492 // If it's a FactoryBean, we want to look at what it creates, not the factory class.
493 return getTypeForFactoryBean(beanName, mbd);
494 }
495 else {
496 return beanClass;
497 }
498 }
499 else {
500 return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
501 }
502 }
503 }
504
505 public String[] getAliases(String name) {
506 String beanName = transformedBeanName(name);
507 List aliases = new ArrayList();
508 boolean factoryPrefix = name.startsWith(FACTORY_BEAN_PREFIX);
509 String fullBeanName = beanName;
510 if (factoryPrefix) {
511 fullBeanName = FACTORY_BEAN_PREFIX + beanName;
512 }
513 if (!fullBeanName.equals(name)) {
514 aliases.add(fullBeanName);
515 }
516 String[] retrievedAliases = super.getAliases(beanName);
517 for (int i = 0; i < retrievedAliases.length; i++) {
518 String alias = (factoryPrefix ? FACTORY_BEAN_PREFIX : "") + retrievedAliases[i];
519 if (!alias.equals(name)) {
520 aliases.add(alias);
521 }
522 }
523 if (!containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
524 BeanFactory parentBeanFactory = getParentBeanFactory();
525 if (parentBeanFactory != null) {
526 aliases.addAll(Arrays.asList(parentBeanFactory.getAliases(fullBeanName)));
527 }
528 }
529 return StringUtils.toStringArray(aliases);
530 }
531
532
533 //---------------------------------------------------------------------
534 // Implementation of HierarchicalBeanFactory interface
535 //---------------------------------------------------------------------
536
537 public BeanFactory getParentBeanFactory() {
538 return this.parentBeanFactory;
539 }
540
541 public boolean containsLocalBean(String name) {
542 String beanName = transformedBeanName(name);
543 return ((containsSingleton(beanName) || containsBeanDefinition(beanName)) &&
544 (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName)));
545 }
546
547
548 //---------------------------------------------------------------------
549 // Implementation of ConfigurableBeanFactory interface
550 //---------------------------------------------------------------------
551
552 public void setParentBeanFactory(BeanFactory parentBeanFactory) {
553 if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {
554 throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
555 }
556 this.parentBeanFactory = parentBeanFactory;
557 }
558
559 public void setBeanClassLoader(ClassLoader beanClassLoader) {
560 this.beanClassLoader = (beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader());
561 }
562
563 public ClassLoader getBeanClassLoader() {
564 return this.beanClassLoader;
565 }
566
567 public void setTempClassLoader(ClassLoader tempClassLoader) {
568 this.tempClassLoader = tempClassLoader;
569 }
570
571 public ClassLoader getTempClassLoader() {
572 return this.tempClassLoader;
573 }
574
575 public void setCacheBeanMetadata(boolean cacheBeanMetadata) {
576 this.cacheBeanMetadata = cacheBeanMetadata;
577 }
578
579 public boolean isCacheBeanMetadata() {
580 return this.cacheBeanMetadata;
581 }
582
583 public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) {
584 Assert.notNull(registrar, "PropertyEditorRegistrar must not be null");
585 this.propertyEditorRegistrars.add(registrar);
586 }
587
588 /**
589 * Return the set of PropertyEditorRegistrars.
590 */
591 public Set getPropertyEditorRegistrars() {
592 return this.propertyEditorRegistrars;
593 }
594
595 public void registerCustomEditor(Class requiredType, Class propertyEditorClass) {
596 Assert.notNull(requiredType, "Required type must not be null");
597 Assert.isAssignable(PropertyEditor.class, propertyEditorClass);
598 this.customEditors.put(requiredType, propertyEditorClass);
599 }
600
601 public void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor) {
602 Assert.notNull(requiredType, "Required type must not be null");
603 Assert.notNull(propertyEditor, "PropertyEditor must not be null");
604 this.customEditors.put(requiredType, propertyEditor);
605 }
606
607 /**
608 * Return the map of custom editors, with Classes as keys
609 * and PropertyEditor instances or PropertyEditor classes as values.
610 */
611 public Map getCustomEditors() {
612 return this.customEditors;
613 }
614
615 public void setTypeConverter(TypeConverter typeConverter) {
616 this.typeConverter = typeConverter;
617 }
618
619 /**
620 * Return the custom TypeConverter to use, if any.
621 * @return the custom TypeConverter, or <code>null</code> if none specified
622 */
623 protected TypeConverter getCustomTypeConverter() {
624 return this.typeConverter;
625 }
626
627 public TypeConverter getTypeConverter() {
628 TypeConverter customConverter = getCustomTypeConverter();
629 if (customConverter != null) {
630 return customConverter;
631 }
632 else {
633 // Build default TypeConverter, registering custom editors.
634 SimpleTypeConverter typeConverter = new SimpleTypeConverter();
635 registerCustomEditors(typeConverter);
636 return typeConverter;
637 }
638 }
639
640 public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
641 Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
642 this.beanPostProcessors.add(beanPostProcessor);
643 if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
644 this.hasInstantiationAwareBeanPostProcessors = true;
645 }
646 if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
647 this.hasDestructionAwareBeanPostProcessors = true;
648 }
649 }
650
651 public int getBeanPostProcessorCount() {
652 return this.beanPostProcessors.size();
653 }
654
655 /**
656 * Return the list of BeanPostProcessors that will get applied
657 * to beans created with this factory.
658 */
659 public List getBeanPostProcessors() {
660 return this.beanPostProcessors;
661 }
662
663 /**
664 * Return whether this factory holds a InstantiationAwareBeanPostProcessor
665 * that will get applied to singleton beans on shutdown.
666 * @see #addBeanPostProcessor
667 * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
668 */
669 protected boolean hasInstantiationAwareBeanPostProcessors() {
670 return this.hasInstantiationAwareBeanPostProcessors;
671 }
672
673 /**
674 * Return whether this factory holds a DestructionAwareBeanPostProcessor
675 * that will get applied to singleton beans on shutdown.
676 * @see #addBeanPostProcessor
677 * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
678 */
679 protected boolean hasDestructionAwareBeanPostProcessors() {
680 return this.hasDestructionAwareBeanPostProcessors;
681 }
682
683 public void registerScope(String scopeName, Scope scope) {
684 Assert.notNull(scopeName, "Scope identifier must not be null");
685 Assert.notNull(scope, "Scope must not be null");
686 if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
687 throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
688 }
689 this.scopes.put(scopeName, scope);
690 }
691
692 public String[] getRegisteredScopeNames() {
693 return StringUtils.toStringArray(this.scopes.keySet());
694 }
695
696 public Scope getRegisteredScope(String scopeName) {
697 Assert.notNull(scopeName, "Scope identifier must not be null");
698 return (Scope) this.scopes.get(scopeName);
699 }
700
701 public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
702 Assert.notNull(otherFactory, "BeanFactory must not be null");
703 setBeanClassLoader(otherFactory.getBeanClassLoader());
704 setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
705 if (otherFactory instanceof AbstractBeanFactory) {
706 AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory;
707 this.customEditors.putAll(otherAbstractFactory.customEditors);
708 this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
709 this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors);
710 this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors ||
711 otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
712 this.hasDestructionAwareBeanPostProcessors = this.hasDestructionAwareBeanPostProcessors ||
713 otherAbstractFactory.hasDestructionAwareBeanPostProcessors;
714 this.scopes.putAll(otherAbstractFactory.scopes);
715 }
716 }
717
718 /**
719 * Return a 'merged' BeanDefinition for the given bean name,
720 * merging a child bean definition with its parent if necessary.
721 * <p>This <code>getMergedBeanDefinition</code> considers bean definition
722 * in ancestors as well.
723 * @param name the name of the bean to retrieve the merged definition for
724 * (may be an alias)
725 * @return a (potentially merged) RootBeanDefinition for the given bean
726 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
727 * @throws BeanDefinitionStoreException in case of an invalid bean definition
728 */
729 public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
730 String beanName = transformedBeanName(name);
731
732 // Efficiently check whether bean definition exists in this factory.
733 if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
734 return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
735 }
736 // Resolve merged bean definition locally.
737 return getMergedLocalBeanDefinition(beanName);
738 }
739
740 public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
741 String beanName = transformedBeanName(name);
742
743 Object beanInstance = getSingleton(beanName, false);
744 if (beanInstance != null) {
745 return (beanInstance instanceof FactoryBean);
746 }
747
748 // No singleton instance found -> check bean definition.
749 if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
750 // No bean definition found in this factory -> delegate to parent.
751 return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
752 }
753
754 return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
755 }
756
757 /**
758 * Callback before prototype creation.
759 * <p>The default implementation register the prototype as currently in creation.
760 * @param beanName the name of the prototype about to be created
761 * @see #isPrototypeCurrentlyInCreation
762 */
763 protected void beforePrototypeCreation(String beanName) {
764 Object curVal = this.prototypesCurrentlyInCreation.get();
765 if (curVal == null) {
766 this.prototypesCurrentlyInCreation.set(beanName);
767 }
768 else if (curVal instanceof String) {
769 Set beanNameSet = new HashSet(2);
770 beanNameSet.add(curVal);
771 beanNameSet.add(beanName);
772 this.prototypesCurrentlyInCreation.set(beanNameSet);
773 }
774 else {
775 Set beanNameSet = (Set) curVal;
776 beanNameSet.add(beanName);
777 }
778 }
779
780 /**
781 * Callback after prototype creation.
782 * <p>The default implementation marks the prototype as not in creation anymore.
783 * @param beanName the name of the prototype that has been created
784 * @see #isPrototypeCurrentlyInCreation
785 */
786 protected void afterPrototypeCreation(String beanName) {
787 Object curVal = this.prototypesCurrentlyInCreation.get();
788 if (curVal instanceof String) {
789 this.prototypesCurrentlyInCreation.set(null);
790 }
791 else if (curVal instanceof Set) {
792 Set beanNameSet = (Set) curVal;
793 beanNameSet.remove(beanName);
794 if (beanNameSet.isEmpty()) {
795 this.prototypesCurrentlyInCreation.set(null);
796 }
797 }
798 }
799
800 /**
801 * Return whether the specified prototype bean is currently in creation
802 * (within the current thread).
803 * @param beanName the name of the bean
804 */
805 protected final boolean isPrototypeCurrentlyInCreation(String beanName) {
806 Object curVal = this.prototypesCurrentlyInCreation.get();
807 return (curVal != null &&
808 (curVal.equals(beanName) || (curVal instanceof Set && ((Set) curVal).contains(beanName))));
809 }
810
811 public boolean isCurrentlyInCreation(String beanName) {
812 return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName);
813 }
814
815 public void destroyBean(String beanName, Object beanInstance) {
816 destroyBean(beanName, beanInstance, getMergedLocalBeanDefinition(beanName));
817 }
818
819 /**
820 * Destroy the given bean instance (usually a prototype instance
821 * obtained from this factory) according to the given bean definition.
822 * @param beanName the name of the bean definition
823 * @param beanInstance the bean instance to destroy
824 * @param mbd the merged bean definition
825 */
826 protected void destroyBean(String beanName, Object beanInstance, RootBeanDefinition mbd) {
827 new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors()).destroy();
828 }
829
830 public void destroyScopedBean(String beanName) {
831 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
832 if (mbd.isSingleton() || mbd.isPrototype()) {
833 throw new IllegalArgumentException(
834 "Bean name '" + beanName + "' does not correspond to an object in a Scope");
835 }
836 String scopeName = mbd.getScope();
837 Scope scope = (Scope) this.scopes.get(scopeName);
838 if (scope == null) {
839 throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
840 }
841 Object bean = scope.remove(beanName);
842 if (bean != null) {
843 destroyBean(beanName, bean, mbd);
844 }
845 }
846
847
848 //---------------------------------------------------------------------
849 // Implementation methods
850 //---------------------------------------------------------------------
851
852 /**
853 * Return the bean name, stripping out the factory dereference prefix if necessary,
854 * and resolving aliases to canonical names.
855 * @param name the user-specified name
856 * @return the transformed bean name
857 */
858 protected String transformedBeanName(String name) {
859 return canonicalName(BeanFactoryUtils.transformedBeanName(name));
860 }
861
862 /**
863 * Determine the original bean name, resolving locally defined aliases to canonical names.
864 * @param name the user-specified name
865 * @return the original bean name
866 */
867 protected String originalBeanName(String name) {
868 String beanName = transformedBeanName(name);
869 if (name.startsWith(FACTORY_BEAN_PREFIX)) {
870 beanName = FACTORY_BEAN_PREFIX + beanName;
871 }
872 return beanName;
873 }
874
875 /**
876 * Initialize the given BeanWrapper with the custom editors registered
877 * with this factory. To be called for BeanWrappers that will create
878 * and populate bean instances.
879 * <p>The default implementation delegates to <code>registerCustomEditors</code>.
880 * Can be overridden in subclasses.
881 * @param bw the BeanWrapper to initialize
882 * @see #registerCustomEditors
883 */
884 protected void initBeanWrapper(BeanWrapper bw) {
885 registerCustomEditors(bw);
886 }
887
888 /**
889 * Initialize the given PropertyEditorRegistry with the custom editors
890 * registered with this BeanFactory.
891 * <p>To be called for BeanWrappers that will create and populate bean
892 * instances, and for SimpleTypeConverter used for constructor argument
893 * and factory method type conversion.
894 * @param registry the PropertyEditorRegistry to initialize
895 */
896 protected void registerCustomEditors(PropertyEditorRegistry registry) {
897 PropertyEditorRegistrySupport registrySupport =
898 (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
899 if (registrySupport != null) {
900 registrySupport.useConfigValueEditors();
901 }
902 if (!this.propertyEditorRegistrars.isEmpty()) {
903 for (Iterator it = this.propertyEditorRegistrars.iterator(); it.hasNext();) {
904 PropertyEditorRegistrar registrar = (PropertyEditorRegistrar) it.next();
905 try {
906 registrar.registerCustomEditors(registry);
907 }
908 catch (BeanCreationException ex) {
909 Throwable rootCause = ex.getMostSpecificCause();
910 if (rootCause instanceof BeanCurrentlyInCreationException) {
911 BeanCreationException bce = (BeanCreationException) rootCause;
912 if (isCurrentlyInCreation(bce.getBeanName())) {
913 if (logger.isDebugEnabled()) {
914 logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
915 "] failed because it tried to obtain currently created bean '" + ex.getBeanName() +
916 "': " + ex.getMessage());
917 }
918 onSuppressedException(ex);
919 continue;
920 }
921 }
922 throw ex;
923 }
924 }
925 }
926 if (!this.customEditors.isEmpty()) {
927 for (Iterator it = this.customEditors.entrySet().iterator(); it.hasNext();) {
928 Map.Entry entry = (Map.Entry) it.next();
929 Class requiredType = (Class) entry.getKey();
930 Object value = entry.getValue();
931 if (value instanceof PropertyEditor) {
932 PropertyEditor editor = (PropertyEditor) value;
933 // Register the editor as shared instance, if possible,
934 // to make it clear that it might be used concurrently.
935 if (registrySupport != null) {
936 registrySupport.registerSharedEditor(requiredType, editor);
937 }
938 else {
939 registry.registerCustomEditor(requiredType, editor);
940 }
941 }
942 else if (value instanceof Class) {
943 Class editorClass = (Class) value;
944 registry.registerCustomEditor(requiredType, (PropertyEditor) BeanUtils.instantiateClass(editorClass));
945 }
946 else {
947 throw new IllegalStateException("Illegal custom editor value type: " + value.getClass().getName());
948 }
949 }
950 }
951 }
952
953
954 /**
955 * Return a merged RootBeanDefinition, traversing the parent bean definition
956 * if the specified bean corresponds to a child bean definition.
957 * @param beanName the name of the bean to retrieve the merged definition for
958 * @return a (potentially merged) RootBeanDefinition for the given bean
959 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
960 * @throws BeanDefinitionStoreException in case of an invalid bean definition
961 */
962 protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
963 // Quick check on the concurrent map first, with minimal locking.
964 RootBeanDefinition mbd = (RootBeanDefinition) this.mergedBeanDefinitions.get(beanName);
965 if (mbd != null) {
966 return mbd;
967 }
968 return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
969 }
970
971 /**
972 * Return a RootBeanDefinition for the given top-level bean, by merging with
973 * the parent if the given bean's definition is a child bean definition.
974 * @param beanName the name of the bean definition
975 * @param bd the original bean definition (Root/ChildBeanDefinition)
976 * @return a (potentially merged) RootBeanDefinition for the given bean
977 * @throws BeanDefinitionStoreException in case of an invalid bean definition
978 */
979 protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
980 throws BeanDefinitionStoreException {
981
982 return getMergedBeanDefinition(beanName, bd, null);
983 }
984
985 /**
986 * Return a RootBeanDefinition for the given bean, by merging with the
987 * parent if the given bean's definition is a child bean definition.
988 * @param beanName the name of the bean definition
989 * @param bd the original bean definition (Root/ChildBeanDefinition)
990 * @param containingBd the containing bean definition in case of inner bean,
991 * or <code>null</code> in case of a top-level bean
992 * @return a (potentially merged) RootBeanDefinition for the given bean
993 * @throws BeanDefinitionStoreException in case of an invalid bean definition
994 */
995 protected RootBeanDefinition getMergedBeanDefinition(
996 String beanName, BeanDefinition bd, BeanDefinition containingBd)
997 throws BeanDefinitionStoreException {
998
999 synchronized (this.mergedBeanDefinitions) {
1000 RootBeanDefinition mbd = null;
1001
1002 // Check with full lock now in order to enforce the same merged instance.
1003 if (containingBd == null) {
1004 mbd = (RootBeanDefinition) this.mergedBeanDefinitions.get(beanName);
1005 }
1006
1007 if (mbd == null) {
1008 if (bd.getParentName() == null) {
1009 // Use copy of given root bean definition.
1010 mbd = new RootBeanDefinition(bd);
1011 }
1012 else {
1013 // Child bean definition: needs to be merged with parent.
1014 BeanDefinition pbd = null;
1015 try {
1016 String parentBeanName = transformedBeanName(bd.getParentName());
1017 if (!beanName.equals(parentBeanName)) {
1018 pbd = getMergedBeanDefinition(parentBeanName);
1019 }
1020 else {
1021 if (getParentBeanFactory() instanceof ConfigurableBeanFactory) {
1022 pbd = ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(parentBeanName);
1023 }
1024 else {
1025 throw new NoSuchBeanDefinitionException(bd.getParentName(),
1026 "Parent name '" + bd.getParentName() + "' is equal to bean name '" + beanName +
1027 "': cannot be resolved without an AbstractBeanFactory parent");
1028 }
1029 }
1030 }
1031 catch (NoSuchBeanDefinitionException ex) {
1032 throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
1033 "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
1034 }
1035 // Deep copy with overridden values.
1036 mbd = new RootBeanDefinition(pbd);
1037 mbd.overrideFrom(bd);
1038 }
1039
1040 // A bean contained in a non-singleton bean cannot be a singleton itself.
1041 // Let's correct this on the fly here, since this might be the result of
1042 // parent-child merging for the outer bean, in which case the original inner bean
1043 // definition will not have inherited the merged outer bean's singleton status.
1044 if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
1045 mbd.setScope(containingBd.getScope());
1046 }
1047
1048 // Only cache the merged bean definition if we're already about to create an
1049 // instance of the bean, or at least have already created an instance before.
1050 if (containingBd == null && isCacheBeanMetadata() && isBeanEligibleForMetadataCaching(beanName)) {
1051 this.mergedBeanDefinitions.put(beanName, mbd);
1052 }
1053 }
1054
1055 return mbd;
1056 }
1057 }
1058
1059 /**
1060 * Check the given merged bean definition,
1061 * potentially throwing validation exceptions.
1062 * @param mbd the merged bean definition to check
1063 * @param beanName the name of the bean
1064 * @param args the arguments for bean creation, if any
1065 * @throws BeanDefinitionStoreException in case of validation failure
1066 */
1067 protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, Object[] args)
1068 throws BeanDefinitionStoreException {
1069
1070 // check if bean definition is not abstract
1071 if (mbd.isAbstract()) {
1072 throw new BeanIsAbstractException(beanName);
1073 }
1074
1075 // Check validity of the usage of the args parameter. This can
1076 // only be used for prototypes constructed via a factory method.
1077 if (args != null && !mbd.isPrototype()) {
1078 throw new BeanDefinitionStoreException(
1079 "Can only specify arguments for the getBean method when referring to a prototype bean definition");
1080 }
1081 }
1082
1083 /**
1084 * Remove the merged bean definition for the specified bean,
1085 * recreating it on next access.
1086 * @param beanName the bean name to clear the merged definition for
1087 */
1088 protected void clearMergedBeanDefinition(String beanName) {
1089 this.mergedBeanDefinitions.remove(beanName);
1090 }
1091
1092 /**
1093 * Resolve the bean class for the specified bean definition,
1094 * resolving a bean class name into a Class reference (if necessary)
1095 * and storing the resolved Class in the bean definition for further use.
1096 * @param mbd the merged bean definition to determine the class for
1097 * @param beanName the name of the bean (for error handling purposes)
1098 * @return the resolved bean class (or <code>null</code> if none)
1099 * @throws CannotLoadBeanClassException if we failed to load the class
1100 */
1101 protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName) {
1102 return resolveBeanClass(mbd, beanName, null);
1103 }
1104
1105 /**
1106 * Resolve the bean class for the specified bean definition,
1107 * resolving a bean class name into a Class reference (if necessary)
1108 * and storing the resolved Class in the bean definition for further use.
1109 * @param mbd the merged bean definition to determine the class for
1110 * @param beanName the name of the bean (for error handling purposes)
1111 * @param typesToMatch the types to match in case of internal type matching purposes
1112 * (also signals that the returned <code>Class</code> will never be exposed to application code)
1113 * @return the resolved bean class (or <code>null</code> if none)
1114 * @throws CannotLoadBeanClassException if we failed to load the class
1115 */
1116 protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName, Class[] typesToMatch)
1117 throws CannotLoadBeanClassException {
1118 try {
1119 if (mbd.hasBeanClass()) {
1120 return mbd.getBeanClass();
1121 }
1122 if (typesToMatch != null) {
1123 ClassLoader tempClassLoader = getTempClassLoader();
1124 if (tempClassLoader != null) {
1125 if (tempClassLoader instanceof DecoratingClassLoader) {
1126 DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
1127 for (int i = 0; i < typesToMatch.length; i++) {
1128 dcl.excludeClass(typesToMatch[i].getName());
1129 }
1130 }
1131 String className = mbd.getBeanClassName();
1132 return (className != null ? ClassUtils.forName(className, tempClassLoader) : null);
1133 }
1134 }
1135 return mbd.resolveBeanClass(getBeanClassLoader());
1136 }
1137 catch (ClassNotFoundException ex) {
1138 throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
1139 }
1140 catch (LinkageError err) {
1141 throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
1142 }
1143 }
1144
1145
1146 /**
1147 * Predict the eventual bean type (of the processed bean instance) for the
1148 * specified bean. Called by {@link #getType} and {@link #isTypeMatch}.
1149 * Does not need to handle FactoryBeans specifically, since it is only
1150 * supposed to operate on the raw bean type.
1151 * <p>This implementation is simplistic in that it is not able to
1152 * handle factory methods and InstantiationAwareBeanPostProcessors.
1153 * It only predicts the bean type correctly for a standard bean.
1154 * To be overridden in subclasses, applying more sophisticated type detection.
1155 * @param beanName the name of the bean
1156 * @param mbd the merged bean definition to determine the type for
1157 * @param typesToMatch the types to match in case of internal type matching purposes
1158 * (also signals that the returned <code>Class</code> will never be exposed to application code)
1159 * @return the type of the bean, or <code>null</code> if not predictable
1160 */
1161 protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) {
1162 if (mbd.getFactoryMethodName() != null) {
1163 return null;
1164 }
1165 return resolveBeanClass(mbd, beanName, typesToMatch);
1166 }
1167
1168 /**
1169 * Check whether the given bean is defined as a {@link FactoryBean}.
1170 * @param beanName the name of the bean
1171 * @param mbd the corresponding bean definition
1172 */
1173 protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
1174 Class beanClass = predictBeanType(beanName, mbd, new Class[] {FactoryBean.class});
1175 return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
1176 }
1177
1178 /**
1179 * Determine the bean type for the given FactoryBean definition, as far as possible.
1180 * Only called if there is no singleton instance registered for the target bean already.
1181 * <p>The default implementation creates the FactoryBean via <code>getBean</code>
1182 * to call its <code>getObjectType</code> method. Subclasses are encouraged to optimize
1183 * this, typically by just instantiating the FactoryBean but not populating it yet,
1184 * trying whether its <code>getObjectType</code> method already returns a type.
1185 * If no type found, a full FactoryBean creation as performed by this implementation
1186 * should be used as fallback.
1187 * @param beanName the name of the bean
1188 * @param mbd the merged bean definition for the bean
1189 * @return the type for the bean if determinable, or <code>null</code> else
1190 * @see org.springframework.beans.factory.FactoryBean#getObjectType()
1191 * @see #getBean(String)
1192 */
1193 protected Class getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
1194 if (!mbd.isSingleton()) {
1195 return null;
1196 }
1197 try {
1198 FactoryBean factoryBean =
1199 (FactoryBean) doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
1200 return getTypeForFactoryBean(factoryBean);
1201 }
1202 catch (BeanCreationException ex) {
1203 // Can only happen when getting a FactoryBean.
1204 if (logger.isDebugEnabled()) {
1205 logger.debug("Ignoring bean creation exception on FactoryBean type check: " + ex);
1206 }
1207 onSuppressedException(ex);
1208 return null;
1209 }
1210 }
1211
1212 /**
1213 * Mark the specified bean as already created (or about to be created).
1214 * <p>This allows the bean factory to optimize its caching for repeated
1215 * creation of the specified bean.
1216 * @param beanName the name of the bean
1217 */
1218 protected void markBeanAsCreated(String beanName) {
1219 this.alreadyCreated.add(beanName);
1220 }
1221
1222 /**
1223 * Determine whether the specified bean is eligible for having
1224 * its bean definition metadata cached.
1225 * @param beanName the name of the bean
1226 * @return <code>true</code> if the bean's metadata may be cached
1227 * at this point already
1228 */
1229 protected boolean isBeanEligibleForMetadataCaching(String beanName) {
1230 return this.alreadyCreated.contains(beanName);
1231 }
1232
1233 /**
1234 * Remove the singleton instance (if any) for the given bean name,
1235 * but only if it hasn't been used for other purposes than type checking.
1236 * @param beanName the name of the bean
1237 * @return <code>true</code> if actually removed, <code>false</code> otherwise
1238 */
1239 protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) {
1240 if (!this.alreadyCreated.contains(beanName)) {
1241 removeSingleton(beanName);
1242 return true;
1243 }
1244 else {
1245 return false;
1246 }
1247 }
1248
1249 /**
1250 * Get the object for the given bean instance, either the bean
1251 * instance itself or its created object in case of a FactoryBean.
1252 * @param beanInstance the shared bean instance
1253 * @param name name that may include factory dereference prefix
1254 * @param beanName the canonical bean name
1255 * @param mbd the merged bean definition
1256 * @return the object to expose for the bean
1257 */
1258 protected Object getObjectForBeanInstance(
1259 Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
1260
1261 // Don't let calling code try to dereference the factory if the bean isn't a factory.
1262 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
1263 throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
1264 }
1265
1266 // Now we have the bean instance, which may be a normal bean or a FactoryBean.
1267 // If it's a FactoryBean, we use it to create a bean instance, unless the
1268 // caller actually wants a reference to the factory.
1269 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
1270 return beanInstance;
1271 }
1272
1273 Object object = null;
1274 if (mbd == null) {
1275 object = getCachedObjectForFactoryBean(beanName);
1276 }
1277 if (object == null) {
1278 // Return bean instance from factory.
1279 FactoryBean factory = (FactoryBean) beanInstance;
1280 // Caches object obtained from FactoryBean if it is a singleton.
1281 if (mbd == null && containsBeanDefinition(beanName)) {
1282 mbd = getMergedLocalBeanDefinition(beanName);
1283 }
1284 boolean synthetic = (mbd != null && mbd.isSynthetic());
1285 object = getObjectFromFactoryBean(factory, beanName, !synthetic);
1286 }
1287 return object;
1288 }
1289
1290 /**
1291 * Determine whether the given bean name is already in use within this factory,
1292 * i.e. whether there is a local bean or alias registered under this name or
1293 * an inner bean created with this name.
1294 * @param beanName the name to check
1295 */
1296 public boolean isBeanNameInUse(String beanName) {
1297 return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
1298 }
1299
1300 /**
1301 * Determine whether the given bean requires destruction on shutdown.
1302 * <p>The default implementation checks the DisposableBean interface as well as
1303 * a specified destroy method and registered DestructionAwareBeanPostProcessors.
1304 * @param bean the bean instance to check
1305 * @param mbd the corresponding bean definition
1306 * @see org.springframework.beans.factory.DisposableBean
1307 * @see AbstractBeanDefinition#getDestroyMethodName()
1308 * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
1309 */
1310 protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
1311 return (bean instanceof DisposableBean || mbd.getDestroyMethodName() != null ||
1312 hasDestructionAwareBeanPostProcessors());
1313 }
1314
1315 /**
1316 * Add the given bean to the list of disposable beans in this factory,
1317 * registering its DisposableBean interface and/or the given destroy method
1318 * to be called on factory shutdown (if applicable). Only applies to singletons.
1319 * @param beanName the name of the bean
1320 * @param bean the bean instance
1321 * @param mbd the bean definition for the bean
1322 * @see RootBeanDefinition#isSingleton
1323 * @see RootBeanDefinition#getDependsOn
1324 * @see #registerDisposableBean
1325 * @see #registerDependentBean
1326 */
1327 protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
1328 if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
1329 if (mbd.isSingleton()) {
1330 // Register a DisposableBean implementation that performs all destruction
1331 // work for the given bean: DestructionAwareBeanPostProcessors,
1332 // DisposableBean interface, custom destroy method.
1333 registerDisposableBean(beanName,
1334 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
1335 }
1336 else {
1337 // A bean with a custom scope...
1338 Scope scope = (Scope) this.scopes.get(mbd.getScope());
1339 if (scope == null) {
1340 throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
1341 }
1342 scope.registerDestructionCallback(beanName,
1343 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
1344 }
1345 }
1346 }
1347
1348
1349 //---------------------------------------------------------------------
1350 // Abstract methods to be implemented by subclasses
1351 //---------------------------------------------------------------------
1352
1353 /**
1354 * Check if this bean factory contains a bean definition with the given name.
1355 * Does not consider any hierarchy this factory may participate in.
1356 * Invoked by <code>containsBean</code> when no cached singleton instance is found.
1357 * <p>Depending on the nature of the concrete bean factory implementation,
1358 * this operation might be expensive (for example, because of directory lookups
1359 * in external registries). However, for listable bean factories, this usually
1360 * just amounts to a local hash lookup: The operation is therefore part of the
1361 * public interface there. The same implementation can serve for both this
1362 * template method and the public interface method in that case.
1363 * @param beanName the name of the bean to look for
1364 * @return if this bean factory contains a bean definition with the given name
1365 * @see #containsBean
1366 * @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition
1367 */
1368 protected abstract boolean containsBeanDefinition(String beanName);
1369
1370 /**
1371 * Return the bean definition for the given bean name.
1372 * Subclasses should normally implement caching, as this method is invoked
1373 * by this class every time bean definition metadata is needed.
1374 * <p>Depending on the nature of the concrete bean factory implementation,
1375 * this operation might be expensive (for example, because of directory lookups
1376 * in external registries). However, for listable bean factories, this usually
1377 * just amounts to a local hash lookup: The operation is therefore part of the
1378 * public interface there. The same implementation can serve for both this
1379 * template method and the public interface method in that case.
1380 * @param beanName the name of the bean to find a definition for
1381 * @return the BeanDefinition for this prototype name (never <code>null</code>)
1382 * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
1383 * if the bean definition cannot be resolved
1384 * @throws BeansException in case of errors
1385 * @see RootBeanDefinition
1386 * @see ChildBeanDefinition
1387 * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
1388 */
1389 protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
1390
1391 /**
1392 * Create a bean instance for the given bean definition.
1393 * The bean definition will already have been merged with the parent
1394 * definition in case of a child definition.
1395 * <p>All the other methods in this class invoke this method, although
1396 * beans may be cached after being instantiated by this method. All bean
1397 * instantiation within this class is performed by this method.
1398 * @param beanName the name of the bean
1399 * @param mbd the merged bean definition for the bean
1400 * @param args arguments to use if creating a prototype using explicit arguments to a
1401 * static factory method. This parameter must be <code>null</code> except in this case.
1402 * @return a new instance of the bean
1403 * @throws BeanCreationException if the bean could not be created
1404 */
1405 protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
1406 throws BeanCreationException;
1407
1408 }