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 && args == 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 public void copyRegisteredEditorsTo(PropertyEditorRegistry registry) {
608 registerCustomEditors(registry);
609 }
610
611 /**
612 * Return the map of custom editors, with Classes as keys
613 * and PropertyEditor instances or PropertyEditor classes as values.
614 */
615 public Map getCustomEditors() {
616 return this.customEditors;
617 }
618
619 public void setTypeConverter(TypeConverter typeConverter) {
620 this.typeConverter = typeConverter;
621 }
622
623 /**
624 * Return the custom TypeConverter to use, if any.
625 * @return the custom TypeConverter, or <code>null</code> if none specified
626 */
627 protected TypeConverter getCustomTypeConverter() {
628 return this.typeConverter;
629 }
630
631 public TypeConverter getTypeConverter() {
632 TypeConverter customConverter = getCustomTypeConverter();
633 if (customConverter != null) {
634 return customConverter;
635 }
636 else {
637 // Build default TypeConverter, registering custom editors.
638 SimpleTypeConverter typeConverter = new SimpleTypeConverter();
639 registerCustomEditors(typeConverter);
640 return typeConverter;
641 }
642 }
643
644 public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
645 Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
646 this.beanPostProcessors.add(beanPostProcessor);
647 if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
648 this.hasInstantiationAwareBeanPostProcessors = true;
649 }
650 if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
651 this.hasDestructionAwareBeanPostProcessors = true;
652 }
653 }
654
655 public int getBeanPostProcessorCount() {
656 return this.beanPostProcessors.size();
657 }
658
659 /**
660 * Return the list of BeanPostProcessors that will get applied
661 * to beans created with this factory.
662 */
663 public List getBeanPostProcessors() {
664 return this.beanPostProcessors;
665 }
666
667 /**
668 * Return whether this factory holds a InstantiationAwareBeanPostProcessor
669 * that will get applied to singleton beans on shutdown.
670 * @see #addBeanPostProcessor
671 * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
672 */
673 protected boolean hasInstantiationAwareBeanPostProcessors() {
674 return this.hasInstantiationAwareBeanPostProcessors;
675 }
676
677 /**
678 * Return whether this factory holds a DestructionAwareBeanPostProcessor
679 * that will get applied to singleton beans on shutdown.
680 * @see #addBeanPostProcessor
681 * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
682 */
683 protected boolean hasDestructionAwareBeanPostProcessors() {
684 return this.hasDestructionAwareBeanPostProcessors;
685 }
686
687 public void registerScope(String scopeName, Scope scope) {
688 Assert.notNull(scopeName, "Scope identifier must not be null");
689 Assert.notNull(scope, "Scope must not be null");
690 if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
691 throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
692 }
693 this.scopes.put(scopeName, scope);
694 }
695
696 public String[] getRegisteredScopeNames() {
697 return StringUtils.toStringArray(this.scopes.keySet());
698 }
699
700 public Scope getRegisteredScope(String scopeName) {
701 Assert.notNull(scopeName, "Scope identifier must not be null");
702 return (Scope) this.scopes.get(scopeName);
703 }
704
705 public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
706 Assert.notNull(otherFactory, "BeanFactory must not be null");
707 setBeanClassLoader(otherFactory.getBeanClassLoader());
708 setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
709 if (otherFactory instanceof AbstractBeanFactory) {
710 AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory;
711 this.customEditors.putAll(otherAbstractFactory.customEditors);
712 this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
713 this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors);
714 this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors ||
715 otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
716 this.hasDestructionAwareBeanPostProcessors = this.hasDestructionAwareBeanPostProcessors ||
717 otherAbstractFactory.hasDestructionAwareBeanPostProcessors;
718 this.scopes.putAll(otherAbstractFactory.scopes);
719 }
720 }
721
722 /**
723 * Return a 'merged' BeanDefinition for the given bean name,
724 * merging a child bean definition with its parent if necessary.
725 * <p>This <code>getMergedBeanDefinition</code> considers bean definition
726 * in ancestors as well.
727 * @param name the name of the bean to retrieve the merged definition for
728 * (may be an alias)
729 * @return a (potentially merged) RootBeanDefinition for the given bean
730 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
731 * @throws BeanDefinitionStoreException in case of an invalid bean definition
732 */
733 public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
734 String beanName = transformedBeanName(name);
735
736 // Efficiently check whether bean definition exists in this factory.
737 if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
738 return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
739 }
740 // Resolve merged bean definition locally.
741 return getMergedLocalBeanDefinition(beanName);
742 }
743
744 public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
745 String beanName = transformedBeanName(name);
746
747 Object beanInstance = getSingleton(beanName, false);
748 if (beanInstance != null) {
749 return (beanInstance instanceof FactoryBean);
750 }
751
752 // No singleton instance found -> check bean definition.
753 if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
754 // No bean definition found in this factory -> delegate to parent.
755 return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
756 }
757
758 return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
759 }
760
761 /**
762 * Callback before prototype creation.
763 * <p>The default implementation register the prototype as currently in creation.
764 * @param beanName the name of the prototype about to be created
765 * @see #isPrototypeCurrentlyInCreation
766 */
767 protected void beforePrototypeCreation(String beanName) {
768 Object curVal = this.prototypesCurrentlyInCreation.get();
769 if (curVal == null) {
770 this.prototypesCurrentlyInCreation.set(beanName);
771 }
772 else if (curVal instanceof String) {
773 Set beanNameSet = new HashSet(2);
774 beanNameSet.add(curVal);
775 beanNameSet.add(beanName);
776 this.prototypesCurrentlyInCreation.set(beanNameSet);
777 }
778 else {
779 Set beanNameSet = (Set) curVal;
780 beanNameSet.add(beanName);
781 }
782 }
783
784 /**
785 * Callback after prototype creation.
786 * <p>The default implementation marks the prototype as not in creation anymore.
787 * @param beanName the name of the prototype that has been created
788 * @see #isPrototypeCurrentlyInCreation
789 */
790 protected void afterPrototypeCreation(String beanName) {
791 Object curVal = this.prototypesCurrentlyInCreation.get();
792 if (curVal instanceof String) {
793 this.prototypesCurrentlyInCreation.set(null);
794 }
795 else if (curVal instanceof Set) {
796 Set beanNameSet = (Set) curVal;
797 beanNameSet.remove(beanName);
798 if (beanNameSet.isEmpty()) {
799 this.prototypesCurrentlyInCreation.set(null);
800 }
801 }
802 }
803
804 /**
805 * Return whether the specified prototype bean is currently in creation
806 * (within the current thread).
807 * @param beanName the name of the bean
808 */
809 protected final boolean isPrototypeCurrentlyInCreation(String beanName) {
810 Object curVal = this.prototypesCurrentlyInCreation.get();
811 return (curVal != null &&
812 (curVal.equals(beanName) || (curVal instanceof Set && ((Set) curVal).contains(beanName))));
813 }
814
815 public boolean isCurrentlyInCreation(String beanName) {
816 return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName);
817 }
818
819 public void destroyBean(String beanName, Object beanInstance) {
820 destroyBean(beanName, beanInstance, getMergedLocalBeanDefinition(beanName));
821 }
822
823 /**
824 * Destroy the given bean instance (usually a prototype instance
825 * obtained from this factory) according to the given bean definition.
826 * @param beanName the name of the bean definition
827 * @param beanInstance the bean instance to destroy
828 * @param mbd the merged bean definition
829 */
830 protected void destroyBean(String beanName, Object beanInstance, RootBeanDefinition mbd) {
831 new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors()).destroy();
832 }
833
834 public void destroyScopedBean(String beanName) {
835 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
836 if (mbd.isSingleton() || mbd.isPrototype()) {
837 throw new IllegalArgumentException(
838 "Bean name '" + beanName + "' does not correspond to an object in a Scope");
839 }
840 String scopeName = mbd.getScope();
841 Scope scope = (Scope) this.scopes.get(scopeName);
842 if (scope == null) {
843 throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
844 }
845 Object bean = scope.remove(beanName);
846 if (bean != null) {
847 destroyBean(beanName, bean, mbd);
848 }
849 }
850
851
852 //---------------------------------------------------------------------
853 // Implementation methods
854 //---------------------------------------------------------------------
855
856 /**
857 * Return the bean name, stripping out the factory dereference prefix if necessary,
858 * and resolving aliases to canonical names.
859 * @param name the user-specified name
860 * @return the transformed bean name
861 */
862 protected String transformedBeanName(String name) {
863 return canonicalName(BeanFactoryUtils.transformedBeanName(name));
864 }
865
866 /**
867 * Determine the original bean name, resolving locally defined aliases to canonical names.
868 * @param name the user-specified name
869 * @return the original bean name
870 */
871 protected String originalBeanName(String name) {
872 String beanName = transformedBeanName(name);
873 if (name.startsWith(FACTORY_BEAN_PREFIX)) {
874 beanName = FACTORY_BEAN_PREFIX + beanName;
875 }
876 return beanName;
877 }
878
879 /**
880 * Initialize the given BeanWrapper with the custom editors registered
881 * with this factory. To be called for BeanWrappers that will create
882 * and populate bean instances.
883 * <p>The default implementation delegates to {@link #registerCustomEditors}.
884 * Can be overridden in subclasses.
885 * @param bw the BeanWrapper to initialize
886 */
887 protected void initBeanWrapper(BeanWrapper bw) {
888 registerCustomEditors(bw);
889 }
890
891 /**
892 * Initialize the given PropertyEditorRegistry with the custom editors
893 * that have been registered with this BeanFactory.
894 * <p>To be called for BeanWrappers that will create and populate bean
895 * instances, and for SimpleTypeConverter used for constructor argument
896 * and factory method type conversion.
897 * @param registry the PropertyEditorRegistry to initialize
898 */
899 protected void registerCustomEditors(PropertyEditorRegistry registry) {
900 PropertyEditorRegistrySupport registrySupport =
901 (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
902 if (registrySupport != null) {
903 registrySupport.useConfigValueEditors();
904 }
905 if (!this.propertyEditorRegistrars.isEmpty()) {
906 for (Iterator it = this.propertyEditorRegistrars.iterator(); it.hasNext();) {
907 PropertyEditorRegistrar registrar = (PropertyEditorRegistrar) it.next();
908 try {
909 registrar.registerCustomEditors(registry);
910 }
911 catch (BeanCreationException ex) {
912 Throwable rootCause = ex.getMostSpecificCause();
913 if (rootCause instanceof BeanCurrentlyInCreationException) {
914 BeanCreationException bce = (BeanCreationException) rootCause;
915 if (isCurrentlyInCreation(bce.getBeanName())) {
916 if (logger.isDebugEnabled()) {
917 logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
918 "] failed because it tried to obtain currently created bean '" + ex.getBeanName() +
919 "': " + ex.getMessage());
920 }
921 onSuppressedException(ex);
922 continue;
923 }
924 }
925 throw ex;
926 }
927 }
928 }
929 if (!this.customEditors.isEmpty()) {
930 for (Iterator it = this.customEditors.entrySet().iterator(); it.hasNext();) {
931 Map.Entry entry = (Map.Entry) it.next();
932 Class requiredType = (Class) entry.getKey();
933 Object value = entry.getValue();
934 if (value instanceof PropertyEditor) {
935 PropertyEditor editor = (PropertyEditor) value;
936 // Register the editor as shared instance, if possible,
937 // to make it clear that it might be used concurrently.
938 if (registrySupport != null) {
939 registrySupport.registerSharedEditor(requiredType, editor);
940 }
941 else {
942 registry.registerCustomEditor(requiredType, editor);
943 }
944 }
945 else if (value instanceof Class) {
946 Class editorClass = (Class) value;
947 registry.registerCustomEditor(requiredType, (PropertyEditor) BeanUtils.instantiateClass(editorClass));
948 }
949 else {
950 throw new IllegalStateException("Illegal custom editor value type: " + value.getClass().getName());
951 }
952 }
953 }
954 }
955
956
957 /**
958 * Return a merged RootBeanDefinition, traversing the parent bean definition
959 * if the specified bean corresponds to a child bean definition.
960 * @param beanName the name of the bean to retrieve the merged definition for
961 * @return a (potentially merged) RootBeanDefinition for the given bean
962 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
963 * @throws BeanDefinitionStoreException in case of an invalid bean definition
964 */
965 protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
966 // Quick check on the concurrent map first, with minimal locking.
967 RootBeanDefinition mbd = (RootBeanDefinition) this.mergedBeanDefinitions.get(beanName);
968 if (mbd != null) {
969 return mbd;
970 }
971 return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
972 }
973
974 /**
975 * Return a RootBeanDefinition for the given top-level bean, by merging with
976 * the parent if the given bean's definition is a child bean definition.
977 * @param beanName the name of the bean definition
978 * @param bd the original bean definition (Root/ChildBeanDefinition)
979 * @return a (potentially merged) RootBeanDefinition for the given bean
980 * @throws BeanDefinitionStoreException in case of an invalid bean definition
981 */
982 protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
983 throws BeanDefinitionStoreException {
984
985 return getMergedBeanDefinition(beanName, bd, null);
986 }
987
988 /**
989 * Return a RootBeanDefinition for the given bean, by merging with the
990 * parent if the given bean's definition is a child bean definition.
991 * @param beanName the name of the bean definition
992 * @param bd the original bean definition (Root/ChildBeanDefinition)
993 * @param containingBd the containing bean definition in case of inner bean,
994 * or <code>null</code> in case of a top-level bean
995 * @return a (potentially merged) RootBeanDefinition for the given bean
996 * @throws BeanDefinitionStoreException in case of an invalid bean definition
997 */
998 protected RootBeanDefinition getMergedBeanDefinition(
999 String beanName, BeanDefinition bd, BeanDefinition containingBd)
1000 throws BeanDefinitionStoreException {
1001
1002 synchronized (this.mergedBeanDefinitions) {
1003 RootBeanDefinition mbd = null;
1004
1005 // Check with full lock now in order to enforce the same merged instance.
1006 if (containingBd == null) {
1007 mbd = (RootBeanDefinition) this.mergedBeanDefinitions.get(beanName);
1008 }
1009
1010 if (mbd == null) {
1011 if (bd.getParentName() == null) {
1012 // Use copy of given root bean definition.
1013 mbd = new RootBeanDefinition(bd);
1014 }
1015 else {
1016 // Child bean definition: needs to be merged with parent.
1017 BeanDefinition pbd = null;
1018 try {
1019 String parentBeanName = transformedBeanName(bd.getParentName());
1020 if (!beanName.equals(parentBeanName)) {
1021 pbd = getMergedBeanDefinition(parentBeanName);
1022 }
1023 else {
1024 if (getParentBeanFactory() instanceof ConfigurableBeanFactory) {
1025 pbd = ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(parentBeanName);
1026 }
1027 else {
1028 throw new NoSuchBeanDefinitionException(bd.getParentName(),
1029 "Parent name '" + bd.getParentName() + "' is equal to bean name '" + beanName +
1030 "': cannot be resolved without an AbstractBeanFactory parent");
1031 }
1032 }
1033 }
1034 catch (NoSuchBeanDefinitionException ex) {
1035 throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
1036 "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
1037 }
1038 // Deep copy with overridden values.
1039 mbd = new RootBeanDefinition(pbd);
1040 mbd.overrideFrom(bd);
1041 }
1042
1043 // A bean contained in a non-singleton bean cannot be a singleton itself.
1044 // Let's correct this on the fly here, since this might be the result of
1045 // parent-child merging for the outer bean, in which case the original inner bean
1046 // definition will not have inherited the merged outer bean's singleton status.
1047 if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
1048 mbd.setScope(containingBd.getScope());
1049 }
1050
1051 // Only cache the merged bean definition if we're already about to create an
1052 // instance of the bean, or at least have already created an instance before.
1053 if (containingBd == null && isCacheBeanMetadata() && isBeanEligibleForMetadataCaching(beanName)) {
1054 this.mergedBeanDefinitions.put(beanName, mbd);
1055 }
1056 }
1057
1058 return mbd;
1059 }
1060 }
1061
1062 /**
1063 * Check the given merged bean definition,
1064 * potentially throwing validation exceptions.
1065 * @param mbd the merged bean definition to check
1066 * @param beanName the name of the bean
1067 * @param args the arguments for bean creation, if any
1068 * @throws BeanDefinitionStoreException in case of validation failure
1069 */
1070 protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, Object[] args)
1071 throws BeanDefinitionStoreException {
1072
1073 // check if bean definition is not abstract
1074 if (mbd.isAbstract()) {
1075 throw new BeanIsAbstractException(beanName);
1076 }
1077
1078 // Check validity of the usage of the args parameter. This can
1079 // only be used for prototypes constructed via a factory method.
1080 if (args != null && !mbd.isPrototype()) {
1081 throw new BeanDefinitionStoreException(
1082 "Can only specify arguments for the getBean method when referring to a prototype bean definition");
1083 }
1084 }
1085
1086 /**
1087 * Remove the merged bean definition for the specified bean,
1088 * recreating it on next access.
1089 * @param beanName the bean name to clear the merged definition for
1090 */
1091 protected void clearMergedBeanDefinition(String beanName) {
1092 this.mergedBeanDefinitions.remove(beanName);
1093 }
1094
1095 /**
1096 * Resolve the bean class for the specified bean definition,
1097 * resolving a bean class name into a Class reference (if necessary)
1098 * and storing the resolved Class in the bean definition for further use.
1099 * @param mbd the merged bean definition to determine the class for
1100 * @param beanName the name of the bean (for error handling purposes)
1101 * @return the resolved bean class (or <code>null</code> if none)
1102 * @throws CannotLoadBeanClassException if we failed to load the class
1103 */
1104 protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName) {
1105 return resolveBeanClass(mbd, beanName, null);
1106 }
1107
1108 /**
1109 * Resolve the bean class for the specified bean definition,
1110 * resolving a bean class name into a Class reference (if necessary)
1111 * and storing the resolved Class in the bean definition for further use.
1112 * @param mbd the merged bean definition to determine the class for
1113 * @param beanName the name of the bean (for error handling purposes)
1114 * @param typesToMatch the types to match in case of internal type matching purposes
1115 * (also signals that the returned <code>Class</code> will never be exposed to application code)
1116 * @return the resolved bean class (or <code>null</code> if none)
1117 * @throws CannotLoadBeanClassException if we failed to load the class
1118 */
1119 protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName, Class[] typesToMatch)
1120 throws CannotLoadBeanClassException {
1121 try {
1122 if (mbd.hasBeanClass()) {
1123 return mbd.getBeanClass();
1124 }
1125 if (typesToMatch != null) {
1126 ClassLoader tempClassLoader = getTempClassLoader();
1127 if (tempClassLoader != null) {
1128 if (tempClassLoader instanceof DecoratingClassLoader) {
1129 DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
1130 for (int i = 0; i < typesToMatch.length; i++) {
1131 dcl.excludeClass(typesToMatch[i].getName());
1132 }
1133 }
1134 String className = mbd.getBeanClassName();
1135 return (className != null ? ClassUtils.forName(className, tempClassLoader) : null);
1136 }
1137 }
1138 return mbd.resolveBeanClass(getBeanClassLoader());
1139 }
1140 catch (ClassNotFoundException ex) {
1141 throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
1142 }
1143 catch (LinkageError err) {
1144 throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
1145 }
1146 }
1147
1148
1149 /**
1150 * Predict the eventual bean type (of the processed bean instance) for the
1151 * specified bean. Called by {@link #getType} and {@link #isTypeMatch}.
1152 * Does not need to handle FactoryBeans specifically, since it is only
1153 * supposed to operate on the raw bean type.
1154 * <p>This implementation is simplistic in that it is not able to
1155 * handle factory methods and InstantiationAwareBeanPostProcessors.
1156 * It only predicts the bean type correctly for a standard bean.
1157 * To be overridden in subclasses, applying more sophisticated type detection.
1158 * @param beanName the name of the bean
1159 * @param mbd the merged bean definition to determine the type for
1160 * @param typesToMatch the types to match in case of internal type matching purposes
1161 * (also signals that the returned <code>Class</code> will never be exposed to application code)
1162 * @return the type of the bean, or <code>null</code> if not predictable
1163 */
1164 protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) {
1165 if (mbd.getFactoryMethodName() != null) {
1166 return null;
1167 }
1168 return resolveBeanClass(mbd, beanName, typesToMatch);
1169 }
1170
1171 /**
1172 * Check whether the given bean is defined as a {@link FactoryBean}.
1173 * @param beanName the name of the bean
1174 * @param mbd the corresponding bean definition
1175 */
1176 protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
1177 Class beanClass = predictBeanType(beanName, mbd, new Class[] {FactoryBean.class});
1178 return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
1179 }
1180
1181 /**
1182 * Determine the bean type for the given FactoryBean definition, as far as possible.
1183 * Only called if there is no singleton instance registered for the target bean already.
1184 * <p>The default implementation creates the FactoryBean via <code>getBean</code>
1185 * to call its <code>getObjectType</code> method. Subclasses are encouraged to optimize
1186 * this, typically by just instantiating the FactoryBean but not populating it yet,
1187 * trying whether its <code>getObjectType</code> method already returns a type.
1188 * If no type found, a full FactoryBean creation as performed by this implementation
1189 * should be used as fallback.
1190 * @param beanName the name of the bean
1191 * @param mbd the merged bean definition for the bean
1192 * @return the type for the bean if determinable, or <code>null</code> else
1193 * @see org.springframework.beans.factory.FactoryBean#getObjectType()
1194 * @see #getBean(String)
1195 */
1196 protected Class getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
1197 if (!mbd.isSingleton()) {
1198 return null;
1199 }
1200 try {
1201 FactoryBean factoryBean =
1202 (FactoryBean) doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
1203 return getTypeForFactoryBean(factoryBean);
1204 }
1205 catch (BeanCreationException ex) {
1206 // Can only happen when getting a FactoryBean.
1207 if (logger.isDebugEnabled()) {
1208 logger.debug("Ignoring bean creation exception on FactoryBean type check: " + ex);
1209 }
1210 onSuppressedException(ex);
1211 return null;
1212 }
1213 }
1214
1215 /**
1216 * Mark the specified bean as already created (or about to be created).
1217 * <p>This allows the bean factory to optimize its caching for repeated
1218 * creation of the specified bean.
1219 * @param beanName the name of the bean
1220 */
1221 protected void markBeanAsCreated(String beanName) {
1222 this.alreadyCreated.add(beanName);
1223 }
1224
1225 /**
1226 * Determine whether the specified bean is eligible for having
1227 * its bean definition metadata cached.
1228 * @param beanName the name of the bean
1229 * @return <code>true</code> if the bean's metadata may be cached
1230 * at this point already
1231 */
1232 protected boolean isBeanEligibleForMetadataCaching(String beanName) {
1233 return this.alreadyCreated.contains(beanName);
1234 }
1235
1236 /**
1237 * Remove the singleton instance (if any) for the given bean name,
1238 * but only if it hasn't been used for other purposes than type checking.
1239 * @param beanName the name of the bean
1240 * @return <code>true</code> if actually removed, <code>false</code> otherwise
1241 */
1242 protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) {
1243 if (!this.alreadyCreated.contains(beanName)) {
1244 removeSingleton(beanName);
1245 return true;
1246 }
1247 else {
1248 return false;
1249 }
1250 }
1251
1252 /**
1253 * Get the object for the given bean instance, either the bean
1254 * instance itself or its created object in case of a FactoryBean.
1255 * @param beanInstance the shared bean instance
1256 * @param name name that may include factory dereference prefix
1257 * @param beanName the canonical bean name
1258 * @param mbd the merged bean definition
1259 * @return the object to expose for the bean
1260 */
1261 protected Object getObjectForBeanInstance(
1262 Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
1263
1264 // Don't let calling code try to dereference the factory if the bean isn't a factory.
1265 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
1266 throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
1267 }
1268
1269 // Now we have the bean instance, which may be a normal bean or a FactoryBean.
1270 // If it's a FactoryBean, we use it to create a bean instance, unless the
1271 // caller actually wants a reference to the factory.
1272 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
1273 return beanInstance;
1274 }
1275
1276 Object object = null;
1277 if (mbd == null) {
1278 object = getCachedObjectForFactoryBean(beanName);
1279 }
1280 if (object == null) {
1281 // Return bean instance from factory.
1282 FactoryBean factory = (FactoryBean) beanInstance;
1283 // Caches object obtained from FactoryBean if it is a singleton.
1284 if (mbd == null && containsBeanDefinition(beanName)) {
1285 mbd = getMergedLocalBeanDefinition(beanName);
1286 }
1287 boolean synthetic = (mbd != null && mbd.isSynthetic());
1288 object = getObjectFromFactoryBean(factory, beanName, !synthetic);
1289 }
1290 return object;
1291 }
1292
1293 /**
1294 * Determine whether the given bean name is already in use within this factory,
1295 * i.e. whether there is a local bean or alias registered under this name or
1296 * an inner bean created with this name.
1297 * @param beanName the name to check
1298 */
1299 public boolean isBeanNameInUse(String beanName) {
1300 return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
1301 }
1302
1303 /**
1304 * Determine whether the given bean requires destruction on shutdown.
1305 * <p>The default implementation checks the DisposableBean interface as well as
1306 * a specified destroy method and registered DestructionAwareBeanPostProcessors.
1307 * @param bean the bean instance to check
1308 * @param mbd the corresponding bean definition
1309 * @see org.springframework.beans.factory.DisposableBean
1310 * @see AbstractBeanDefinition#getDestroyMethodName()
1311 * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
1312 */
1313 protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
1314 return (bean instanceof DisposableBean || mbd.getDestroyMethodName() != null ||
1315 hasDestructionAwareBeanPostProcessors());
1316 }
1317
1318 /**
1319 * Add the given bean to the list of disposable beans in this factory,
1320 * registering its DisposableBean interface and/or the given destroy method
1321 * to be called on factory shutdown (if applicable). Only applies to singletons.
1322 * @param beanName the name of the bean
1323 * @param bean the bean instance
1324 * @param mbd the bean definition for the bean
1325 * @see RootBeanDefinition#isSingleton
1326 * @see RootBeanDefinition#getDependsOn
1327 * @see #registerDisposableBean
1328 * @see #registerDependentBean
1329 */
1330 protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
1331 if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
1332 if (mbd.isSingleton()) {
1333 // Register a DisposableBean implementation that performs all destruction
1334 // work for the given bean: DestructionAwareBeanPostProcessors,
1335 // DisposableBean interface, custom destroy method.
1336 registerDisposableBean(beanName,
1337 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
1338 }
1339 else {
1340 // A bean with a custom scope...
1341 Scope scope = (Scope) this.scopes.get(mbd.getScope());
1342 if (scope == null) {
1343 throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
1344 }
1345 scope.registerDestructionCallback(beanName,
1346 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
1347 }
1348 }
1349 }
1350
1351
1352 //---------------------------------------------------------------------
1353 // Abstract methods to be implemented by subclasses
1354 //---------------------------------------------------------------------
1355
1356 /**
1357 * Check if this bean factory contains a bean definition with the given name.
1358 * Does not consider any hierarchy this factory may participate in.
1359 * Invoked by <code>containsBean</code> when no cached singleton instance is found.
1360 * <p>Depending on the nature of the concrete bean factory implementation,
1361 * this operation might be expensive (for example, because of directory lookups
1362 * in external registries). However, for listable bean factories, this usually
1363 * just amounts to a local hash lookup: The operation is therefore part of the
1364 * public interface there. The same implementation can serve for both this
1365 * template method and the public interface method in that case.
1366 * @param beanName the name of the bean to look for
1367 * @return if this bean factory contains a bean definition with the given name
1368 * @see #containsBean
1369 * @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition
1370 */
1371 protected abstract boolean containsBeanDefinition(String beanName);
1372
1373 /**
1374 * Return the bean definition for the given bean name.
1375 * Subclasses should normally implement caching, as this method is invoked
1376 * by this class every time bean definition metadata is needed.
1377 * <p>Depending on the nature of the concrete bean factory implementation,
1378 * this operation might be expensive (for example, because of directory lookups
1379 * in external registries). However, for listable bean factories, this usually
1380 * just amounts to a local hash lookup: The operation is therefore part of the
1381 * public interface there. The same implementation can serve for both this
1382 * template method and the public interface method in that case.
1383 * @param beanName the name of the bean to find a definition for
1384 * @return the BeanDefinition for this prototype name (never <code>null</code>)
1385 * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
1386 * if the bean definition cannot be resolved
1387 * @throws BeansException in case of errors
1388 * @see RootBeanDefinition
1389 * @see ChildBeanDefinition
1390 * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
1391 */
1392 protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
1393
1394 /**
1395 * Create a bean instance for the given bean definition.
1396 * The bean definition will already have been merged with the parent
1397 * definition in case of a child definition.
1398 * <p>All the other methods in this class invoke this method, although
1399 * beans may be cached after being instantiated by this method. All bean
1400 * instantiation within this class is performed by this method.
1401 * @param beanName the name of the bean
1402 * @param mbd the merged bean definition for the bean
1403 * @param args arguments to use if creating a prototype using explicit arguments to a
1404 * static factory method. This parameter must be <code>null</code> except in this case.
1405 * @return a new instance of the bean
1406 * @throws BeanCreationException if the bean could not be created
1407 */
1408 protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
1409 throws BeanCreationException;
1410
1411 }