0001: /*
0002: * Copyright 2002-2007 the original author or authors.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.springframework.beans.factory.support;
0018:
0019: import java.beans.PropertyEditor;
0020: import java.util.ArrayList;
0021: import java.util.Arrays;
0022: import java.util.Collections;
0023: import java.util.HashMap;
0024: import java.util.HashSet;
0025: import java.util.Iterator;
0026: import java.util.List;
0027: import java.util.Map;
0028: import java.util.Set;
0029:
0030: import org.springframework.beans.BeanWrapper;
0031: import org.springframework.beans.BeansException;
0032: import org.springframework.beans.PropertyEditorRegistrar;
0033: import org.springframework.beans.PropertyEditorRegistry;
0034: import org.springframework.beans.PropertyEditorRegistrySupport;
0035: import org.springframework.beans.SimpleTypeConverter;
0036: import org.springframework.beans.TypeConverter;
0037: import org.springframework.beans.factory.BeanCreationException;
0038: import org.springframework.beans.factory.BeanCurrentlyInCreationException;
0039: import org.springframework.beans.factory.BeanDefinitionStoreException;
0040: import org.springframework.beans.factory.BeanFactory;
0041: import org.springframework.beans.factory.BeanFactoryUtils;
0042: import org.springframework.beans.factory.BeanIsAbstractException;
0043: import org.springframework.beans.factory.BeanIsNotAFactoryException;
0044: import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
0045: import org.springframework.beans.factory.CannotLoadBeanClassException;
0046: import org.springframework.beans.factory.DisposableBean;
0047: import org.springframework.beans.factory.FactoryBean;
0048: import org.springframework.beans.factory.FactoryBeanNotInitializedException;
0049: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
0050: import org.springframework.beans.factory.ObjectFactory;
0051: import org.springframework.beans.factory.SmartFactoryBean;
0052: import org.springframework.beans.factory.config.BeanDefinition;
0053: import org.springframework.beans.factory.config.BeanPostProcessor;
0054: import org.springframework.beans.factory.config.ConfigurableBeanFactory;
0055: import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
0056: import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
0057: import org.springframework.beans.factory.config.Scope;
0058: import org.springframework.core.CollectionFactory;
0059: import org.springframework.util.Assert;
0060: import org.springframework.util.ClassUtils;
0061: import org.springframework.util.StringUtils;
0062:
0063: /**
0064: * Abstract base class for {@link org.springframework.beans.factory.BeanFactory}
0065: * implementations, providing the full capabilities of the
0066: * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory} SPI.
0067: * Does <i>not</i> assume a listable bean factory: can therefore also be used
0068: * as base class for bean factory implementations which obtain bean definitions
0069: * from some backend resource (where bean definition access is an expensive operation).
0070: *
0071: * <p>This class provides a singleton cache (through its base class
0072: * {@link org.springframework.beans.factory.support.DefaultSingletonBeanRegistry},
0073: * singleton/prototype determination, {@link org.springframework.beans.factory.FactoryBean}
0074: * handling, aliases, bean definition merging for child bean definitions,
0075: * and bean destruction ({@link org.springframework.beans.factory.DisposableBean}
0076: * interface, custom destroy methods). Furthermore, it can manage a bean factory
0077: * hierarchy (delegating to the parent in case of an unknown bean), through implementing
0078: * the {@link org.springframework.beans.factory.HierarchicalBeanFactory} interface.
0079: *
0080: * <p>The main template methods to be implemented by subclasses are
0081: * {@link #getBeanDefinition} and {@link #createBean}, retrieving a bean definition
0082: * for a given bean name and creating a bean instance for a given bean definition,
0083: * respectively. Default implementations of those operations can be found in
0084: * {@link DefaultListableBeanFactory} and {@link AbstractAutowireCapableBeanFactory}.
0085: *
0086: * @author Rod Johnson
0087: * @author Juergen Hoeller
0088: * @since 15 April 2001
0089: * @see #getBeanDefinition
0090: * @see #createBean
0091: * @see AbstractAutowireCapableBeanFactory#createBean
0092: * @see DefaultListableBeanFactory#getBeanDefinition
0093: */
0094: public abstract class AbstractBeanFactory extends
0095: DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
0096:
0097: /** Parent bean factory, for bean inheritance support */
0098: private BeanFactory parentBeanFactory;
0099:
0100: /** ClassLoader to resolve bean class names with, if necessary */
0101: private ClassLoader beanClassLoader = ClassUtils
0102: .getDefaultClassLoader();
0103:
0104: /** Whether to cache bean metadata or rather reobtain it for every access */
0105: private boolean cacheBeanMetadata = true;
0106:
0107: /** Custom PropertyEditors to apply to the beans of this factory */
0108: private final Map customEditors = new HashMap();
0109:
0110: /** Custom PropertyEditorRegistrars to apply to the beans of this factory */
0111: private final Set propertyEditorRegistrars = CollectionFactory
0112: .createLinkedSetIfPossible(16);
0113:
0114: /** BeanPostProcessors to apply in createBean */
0115: private final List beanPostProcessors = new ArrayList();
0116:
0117: /** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */
0118: private boolean hasInstantiationAwareBeanPostProcessors;
0119:
0120: /** Indicates whether any DestructionAwareBeanPostProcessors have been registered */
0121: private boolean hasDestructionAwareBeanPostProcessors;
0122:
0123: /** Map from scope identifier String to corresponding Scope */
0124: private final Map scopes = new HashMap();
0125:
0126: /** Map from alias to canonical bean name */
0127: private final Map aliasMap = CollectionFactory
0128: .createConcurrentMapIfPossible(16);
0129:
0130: /** Map from bean name to merged RootBeanDefinition */
0131: private final Map mergedBeanDefinitions = CollectionFactory
0132: .createConcurrentMapIfPossible(16);
0133:
0134: /** Names of beans that have already been created at least once */
0135: private final Set alreadyCreated = Collections
0136: .synchronizedSet(new HashSet());
0137:
0138: /** Names of beans that are currently in creation */
0139: private final ThreadLocal prototypesCurrentlyInCreation = new ThreadLocal();
0140:
0141: /** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
0142: private final Map factoryBeanObjectCache = new HashMap();
0143:
0144: /**
0145: * Create a new AbstractBeanFactory.
0146: */
0147: public AbstractBeanFactory() {
0148: }
0149:
0150: /**
0151: * Create a new AbstractBeanFactory with the given parent.
0152: * @param parentBeanFactory parent bean factory, or <code>null</code> if none
0153: * @see #getBean
0154: */
0155: public AbstractBeanFactory(BeanFactory parentBeanFactory) {
0156: this .parentBeanFactory = parentBeanFactory;
0157: }
0158:
0159: //---------------------------------------------------------------------
0160: // Implementation of BeanFactory interface
0161: //---------------------------------------------------------------------
0162:
0163: public Object getBean(String name) throws BeansException {
0164: return getBean(name, null, null);
0165: }
0166:
0167: public Object getBean(String name, Class requiredType)
0168: throws BeansException {
0169: return getBean(name, requiredType, null);
0170: }
0171:
0172: /**
0173: * Return an instance, which may be shared or independent, of the specified bean.
0174: * @param name the name of the bean to retrieve
0175: * @param args arguments to use if creating a prototype using explicit arguments to a
0176: * static factory method. It is invalid to use a non-null args value in any other case.
0177: * @return an instance of the bean
0178: * @throws BeansException if the bean could not be created
0179: */
0180: public Object getBean(String name, Object[] args)
0181: throws BeansException {
0182: return getBean(name, null, args);
0183: }
0184:
0185: /**
0186: * Return an instance, which may be shared or independent, of the specified bean.
0187: * @param name the name of the bean to retrieve
0188: * @param requiredType the required type of the bean to retrieve
0189: * @param args arguments to use if creating a prototype using explicit arguments to a
0190: * static factory method. It is invalid to use a non-null args value in any other case.
0191: * @return an instance of the bean
0192: * @throws BeansException if the bean could not be created
0193: */
0194: public Object getBean(String name, Class requiredType,
0195: final Object[] args) throws BeansException {
0196: final String beanName = transformedBeanName(name);
0197: Object bean = null;
0198:
0199: // Eagerly check singleton cache for manually registered singletons.
0200: Object sharedInstance = getSingleton(beanName);
0201: if (sharedInstance != null) {
0202: if (isSingletonCurrentlyInCreation(beanName)) {
0203: if (logger.isDebugEnabled()) {
0204: logger
0205: .debug("Returning eagerly cached instance of singleton bean '"
0206: + beanName
0207: + "' that is not fully initialized yet - a consequence of a circular reference");
0208: }
0209: } else {
0210: if (logger.isDebugEnabled()) {
0211: logger
0212: .debug("Returning cached instance of singleton bean '"
0213: + beanName + "'");
0214: }
0215: }
0216: if (containsBeanDefinition(beanName)) {
0217: RootBeanDefinition mbd = getMergedBeanDefinition(
0218: beanName, false);
0219: bean = getObjectForBeanInstance(sharedInstance, name,
0220: mbd);
0221: } else {
0222: bean = getObjectForBeanInstance(sharedInstance, name,
0223: null);
0224: }
0225: }
0226:
0227: else {
0228: // Fail if we're already creating this bean instance:
0229: // We're assumably within a circular reference.
0230: if (isPrototypeCurrentlyInCreation(beanName)) {
0231: throw new BeanCurrentlyInCreationException(beanName);
0232: }
0233:
0234: // Check if bean definition exists in this factory.
0235: BeanFactory parentBeanFactory = getParentBeanFactory();
0236: if (parentBeanFactory != null
0237: && !containsBeanDefinition(beanName)) {
0238: // Not found -> check parent.
0239: String nameToLookup = originalBeanName(name);
0240: if (parentBeanFactory instanceof AbstractBeanFactory) {
0241: // Delegation to parent with args only possible for AbstractBeanFactory.
0242: return ((AbstractBeanFactory) parentBeanFactory)
0243: .getBean(nameToLookup, requiredType, args);
0244: } else if (args == null) {
0245: // No args -> delegate to standard getBean method.
0246: return parentBeanFactory.getBean(nameToLookup,
0247: requiredType);
0248: } else {
0249: throw new NoSuchBeanDefinitionException(
0250: beanName,
0251: "Cannot delegate to parent BeanFactory because it does not supported passed-in arguments");
0252: }
0253: }
0254:
0255: this .alreadyCreated.add(beanName);
0256:
0257: final RootBeanDefinition mbd = getMergedBeanDefinition(
0258: beanName, false);
0259: checkMergedBeanDefinition(mbd, beanName, args);
0260:
0261: // Create bean instance.
0262: if (mbd.isSingleton()) {
0263: sharedInstance = getSingleton(beanName,
0264: new ObjectFactory() {
0265: public Object getObject()
0266: throws BeansException {
0267: try {
0268: return createBean(beanName, mbd,
0269: args);
0270: } catch (BeansException ex) {
0271: // Explicitly remove instance from singleton cache: It might have been put there
0272: // eagerly by the creation process, to allow for circular reference resolution.
0273: // Also remove any beans that received a temporary reference to the bean.
0274: destroySingleton(beanName);
0275: throw ex;
0276: }
0277: }
0278: });
0279: bean = getObjectForBeanInstance(sharedInstance, name,
0280: mbd);
0281: }
0282:
0283: else if (mbd.isPrototype()) {
0284: // It's a prototype -> create a new instance.
0285: Object prototypeInstance = null;
0286: try {
0287: beforePrototypeCreation(beanName);
0288: prototypeInstance = createBean(beanName, mbd, args);
0289: } finally {
0290: afterPrototypeCreation(beanName);
0291: }
0292: bean = getObjectForBeanInstance(prototypeInstance,
0293: name, mbd);
0294: }
0295:
0296: else {
0297: String scopeName = mbd.getScope();
0298: final Scope scope = (Scope) this .scopes.get(scopeName);
0299: if (scope == null) {
0300: throw new IllegalStateException(
0301: "No Scope registered for scope '"
0302: + scopeName + "'");
0303: }
0304: try {
0305: Object scopedInstance = scope.get(beanName,
0306: new ObjectFactory() {
0307: public Object getObject()
0308: throws BeansException {
0309: beforePrototypeCreation(beanName);
0310: try {
0311: Object bean = createBean(
0312: beanName, mbd, args);
0313: if (requiresDestruction(bean,
0314: mbd)) {
0315: scope
0316: .registerDestructionCallback(
0317: beanName,
0318: new DisposableBeanAdapter(
0319: bean,
0320: beanName,
0321: mbd,
0322: getBeanPostProcessors()));
0323: }
0324: return bean;
0325: } finally {
0326: afterPrototypeCreation(beanName);
0327: }
0328: }
0329: });
0330: bean = getObjectForBeanInstance(scopedInstance,
0331: name, mbd);
0332: } catch (IllegalStateException ex) {
0333: throw new BeanCreationException(
0334: beanName,
0335: "Scope '"
0336: + scopeName
0337: + "' is not active for the current thread; "
0338: + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
0339: ex);
0340: }
0341: }
0342: }
0343:
0344: // Check if required type matches the type of the actual bean instance.
0345: if (requiredType != null
0346: && !requiredType.isAssignableFrom(bean.getClass())) {
0347: throw new BeanNotOfRequiredTypeException(name,
0348: requiredType, bean.getClass());
0349: }
0350: return bean;
0351: }
0352:
0353: public boolean containsBean(String name) {
0354: String beanName = transformedBeanName(name);
0355: if (containsSingleton(beanName)
0356: || containsBeanDefinition(beanName)) {
0357: return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
0358: }
0359: // Not found -> check parent.
0360: BeanFactory parentBeanFactory = getParentBeanFactory();
0361: return (parentBeanFactory != null && parentBeanFactory
0362: .containsBean(originalBeanName(name)));
0363: }
0364:
0365: public boolean isSingleton(String name)
0366: throws NoSuchBeanDefinitionException {
0367: String beanName = transformedBeanName(name);
0368:
0369: Object beanInstance = getSingleton(beanName);
0370: if (beanInstance != null) {
0371: if (beanInstance instanceof FactoryBean) {
0372: return (BeanFactoryUtils.isFactoryDereference(name) || ((FactoryBean) beanInstance)
0373: .isSingleton());
0374: } else {
0375: return !BeanFactoryUtils.isFactoryDereference(name);
0376: }
0377: }
0378:
0379: else {
0380: // No singleton instance found -> check bean definition.
0381: BeanFactory parentBeanFactory = getParentBeanFactory();
0382: if (parentBeanFactory != null
0383: && !containsBeanDefinition(beanName)) {
0384: // No bean definition found in this factory -> delegate to parent.
0385: return parentBeanFactory
0386: .isSingleton(originalBeanName(name));
0387: }
0388:
0389: RootBeanDefinition bd = getMergedBeanDefinition(beanName,
0390: false);
0391:
0392: // In case of FactoryBean, return singleton status of created object if not a dereference.
0393: if (bd.isSingleton()) {
0394: if (isBeanClassMatch(beanName, bd, FactoryBean.class)) {
0395: if (BeanFactoryUtils.isFactoryDereference(name)) {
0396: return true;
0397: }
0398: FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX
0399: + beanName);
0400: return factoryBean.isSingleton();
0401: } else {
0402: return !BeanFactoryUtils.isFactoryDereference(name);
0403: }
0404: } else {
0405: return false;
0406: }
0407: }
0408: }
0409:
0410: public boolean isPrototype(String name)
0411: throws NoSuchBeanDefinitionException {
0412: String beanName = transformedBeanName(name);
0413:
0414: BeanFactory parentBeanFactory = getParentBeanFactory();
0415: if (parentBeanFactory != null
0416: && !containsBeanDefinition(beanName)) {
0417: // No bean definition found in this factory -> delegate to parent.
0418: return parentBeanFactory
0419: .isPrototype(originalBeanName(name));
0420: }
0421:
0422: RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
0423:
0424: // In case of FactoryBean, return singleton status of created object if not a dereference.
0425: if (bd.isPrototype()) {
0426: return (!BeanFactoryUtils.isFactoryDereference(name) || isBeanClassMatch(
0427: beanName, bd, FactoryBean.class));
0428: } else {
0429: // Singleton or scoped - not a prototype.
0430: // However, FactoryBean may still produce a prototype object...
0431: if (!BeanFactoryUtils.isFactoryDereference(name)
0432: && isBeanClassMatch(beanName, bd, FactoryBean.class)) {
0433: FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX
0434: + beanName);
0435: return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean)
0436: .isPrototype()) || !factoryBean.isSingleton());
0437: } else {
0438: return false;
0439: }
0440: }
0441: }
0442:
0443: public boolean isTypeMatch(String name, Class targetType)
0444: throws NoSuchBeanDefinitionException {
0445: String beanName = transformedBeanName(name);
0446: Class typeToMatch = (targetType != null ? targetType
0447: : Object.class);
0448:
0449: // Check manually registered singletons.
0450: Object beanInstance = getSingleton(beanName);
0451: if (beanInstance != null) {
0452: if (beanInstance instanceof FactoryBean) {
0453: if (!BeanFactoryUtils.isFactoryDereference(name)) {
0454: Class type = getTypeForFactoryBean((FactoryBean) beanInstance);
0455: return (type != null && typeToMatch
0456: .isAssignableFrom(type));
0457: } else {
0458: return typeToMatch.isAssignableFrom(beanInstance
0459: .getClass());
0460: }
0461: } else {
0462: return !BeanFactoryUtils.isFactoryDereference(name)
0463: && typeToMatch.isAssignableFrom(beanInstance
0464: .getClass());
0465: }
0466: }
0467:
0468: else {
0469: // No singleton instance found -> check bean definition.
0470: BeanFactory parentBeanFactory = getParentBeanFactory();
0471: if (parentBeanFactory != null
0472: && !containsBeanDefinition(beanName)) {
0473: // No bean definition found in this factory -> delegate to parent.
0474: return parentBeanFactory.isTypeMatch(
0475: originalBeanName(name), targetType);
0476: }
0477:
0478: RootBeanDefinition mbd = getMergedBeanDefinition(beanName,
0479: false);
0480: Class beanClass = predictBeanType(beanName, mbd);
0481:
0482: if (beanClass == null) {
0483: return false;
0484: }
0485:
0486: // Check bean class whether we're dealing with a FactoryBean.
0487: if (FactoryBean.class.isAssignableFrom(beanClass)) {
0488: if (!BeanFactoryUtils.isFactoryDereference(name)) {
0489: // If it's a FactoryBean, we want to look at what it creates, not the factory class.
0490: Class type = getTypeForFactoryBean(beanName, mbd);
0491: return (type != null && typeToMatch
0492: .isAssignableFrom(type));
0493: } else {
0494: return typeToMatch.isAssignableFrom(beanClass);
0495: }
0496: } else {
0497: return !BeanFactoryUtils.isFactoryDereference(name)
0498: && typeToMatch.isAssignableFrom(beanClass);
0499: }
0500: }
0501: }
0502:
0503: public Class getType(String name)
0504: throws NoSuchBeanDefinitionException {
0505: String beanName = transformedBeanName(name);
0506:
0507: // Check manually registered singletons.
0508: Object beanInstance = getSingleton(beanName);
0509: if (beanInstance != null) {
0510: if (beanInstance instanceof FactoryBean
0511: && !BeanFactoryUtils.isFactoryDereference(name)) {
0512: return getTypeForFactoryBean((FactoryBean) beanInstance);
0513: } else {
0514: return beanInstance.getClass();
0515: }
0516: }
0517:
0518: else {
0519: // No singleton instance found -> check bean definition.
0520: BeanFactory parentBeanFactory = getParentBeanFactory();
0521: if (parentBeanFactory != null
0522: && !containsBeanDefinition(beanName)) {
0523: // No bean definition found in this factory -> delegate to parent.
0524: return parentBeanFactory
0525: .getType(originalBeanName(name));
0526: }
0527:
0528: RootBeanDefinition mbd = getMergedBeanDefinition(beanName,
0529: false);
0530: Class beanClass = predictBeanType(beanName, mbd);
0531:
0532: // Check bean class whether we're dealing with a FactoryBean.
0533: if (beanClass != null
0534: && FactoryBean.class.isAssignableFrom(beanClass)) {
0535: if (!BeanFactoryUtils.isFactoryDereference(name)) {
0536: // If it's a FactoryBean, we want to look at what it creates, not the factory class.
0537: return getTypeForFactoryBean(beanName, mbd);
0538: } else {
0539: return beanClass;
0540: }
0541: } else {
0542: return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass
0543: : null);
0544: }
0545: }
0546: }
0547:
0548: public String[] getAliases(String name) {
0549: String beanName = transformedBeanName(name);
0550: List aliases = new ArrayList();
0551: boolean factoryPrefix = name.startsWith(FACTORY_BEAN_PREFIX);
0552: String fullBeanName = beanName;
0553: if (factoryPrefix) {
0554: fullBeanName = FACTORY_BEAN_PREFIX + beanName;
0555: }
0556: if (!fullBeanName.equals(name)) {
0557: aliases.add(fullBeanName);
0558: }
0559: synchronized (this .aliasMap) {
0560: for (Iterator it = this .aliasMap.entrySet().iterator(); it
0561: .hasNext();) {
0562: Map.Entry entry = (Map.Entry) it.next();
0563: if (entry.getValue().equals(beanName)) {
0564: String key = (factoryPrefix ? FACTORY_BEAN_PREFIX
0565: : "")
0566: + entry.getKey();
0567: if (!key.equals(name)) {
0568: aliases.add(key);
0569: }
0570: }
0571: }
0572: }
0573: if (!containsSingleton(beanName)
0574: && !containsBeanDefinition(beanName)) {
0575: BeanFactory parentBeanFactory = getParentBeanFactory();
0576: if (parentBeanFactory != null) {
0577: aliases.addAll(Arrays.asList(parentBeanFactory
0578: .getAliases(fullBeanName)));
0579: }
0580: }
0581: return StringUtils.toStringArray(aliases);
0582: }
0583:
0584: //---------------------------------------------------------------------
0585: // Implementation of HierarchicalBeanFactory interface
0586: //---------------------------------------------------------------------
0587:
0588: public BeanFactory getParentBeanFactory() {
0589: return this .parentBeanFactory;
0590: }
0591:
0592: public boolean containsLocalBean(String name) {
0593: String beanName = transformedBeanName(name);
0594: return ((containsSingleton(beanName) || containsBeanDefinition(beanName)) && (!BeanFactoryUtils
0595: .isFactoryDereference(name) || isFactoryBean(beanName)));
0596: }
0597:
0598: //---------------------------------------------------------------------
0599: // Implementation of ConfigurableBeanFactory interface
0600: //---------------------------------------------------------------------
0601:
0602: public void setParentBeanFactory(BeanFactory parentBeanFactory) {
0603: if (this .parentBeanFactory != null
0604: && this .parentBeanFactory != parentBeanFactory) {
0605: throw new IllegalStateException(
0606: "Already associated with parent BeanFactory: "
0607: + this .parentBeanFactory);
0608: }
0609: this .parentBeanFactory = parentBeanFactory;
0610: }
0611:
0612: public void setBeanClassLoader(ClassLoader beanClassLoader) {
0613: this .beanClassLoader = (beanClassLoader != null ? beanClassLoader
0614: : ClassUtils.getDefaultClassLoader());
0615: }
0616:
0617: public ClassLoader getBeanClassLoader() {
0618: return this .beanClassLoader;
0619: }
0620:
0621: public void setCacheBeanMetadata(boolean cacheBeanMetadata) {
0622: this .cacheBeanMetadata = cacheBeanMetadata;
0623: }
0624:
0625: public boolean isCacheBeanMetadata() {
0626: return this .cacheBeanMetadata;
0627: }
0628:
0629: public void addPropertyEditorRegistrar(
0630: PropertyEditorRegistrar registrar) {
0631: Assert.notNull(registrar,
0632: "PropertyEditorRegistrar must not be null");
0633: this .propertyEditorRegistrars.add(registrar);
0634: }
0635:
0636: /**
0637: * Return the set of PropertyEditorRegistrars.
0638: */
0639: public Set getPropertyEditorRegistrars() {
0640: return this .propertyEditorRegistrars;
0641: }
0642:
0643: public void registerCustomEditor(Class requiredType,
0644: PropertyEditor propertyEditor) {
0645: Assert.notNull(requiredType, "Required type must not be null");
0646: Assert.notNull(propertyEditor,
0647: "PropertyEditor must not be null");
0648: this .customEditors.put(requiredType, propertyEditor);
0649: }
0650:
0651: /**
0652: * Return the map of custom editors, with Classes as keys
0653: * and PropertyEditors as values.
0654: */
0655: public Map getCustomEditors() {
0656: return this .customEditors;
0657: }
0658:
0659: public TypeConverter getTypeConverter() {
0660: SimpleTypeConverter typeConverter = new SimpleTypeConverter();
0661: registerCustomEditors(typeConverter);
0662: return typeConverter;
0663: }
0664:
0665: public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
0666: Assert.notNull(beanPostProcessor,
0667: "BeanPostProcessor must not be null");
0668: this .beanPostProcessors.add(beanPostProcessor);
0669: if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
0670: this .hasInstantiationAwareBeanPostProcessors = true;
0671: }
0672: if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
0673: this .hasDestructionAwareBeanPostProcessors = true;
0674: }
0675: }
0676:
0677: public int getBeanPostProcessorCount() {
0678: return this .beanPostProcessors.size();
0679: }
0680:
0681: /**
0682: * Return the list of BeanPostProcessors that will get applied
0683: * to beans created with this factory.
0684: */
0685: public List getBeanPostProcessors() {
0686: return this .beanPostProcessors;
0687: }
0688:
0689: /**
0690: * Return whether this factory holds a InstantiationAwareBeanPostProcessor
0691: * that will get applied to singleton beans on shutdown.
0692: * @see #addBeanPostProcessor
0693: * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
0694: */
0695: protected boolean hasInstantiationAwareBeanPostProcessors() {
0696: return this .hasInstantiationAwareBeanPostProcessors;
0697: }
0698:
0699: /**
0700: * Return whether this factory holds a DestructionAwareBeanPostProcessor
0701: * that will get applied to singleton beans on shutdown.
0702: * @see #addBeanPostProcessor
0703: * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
0704: */
0705: protected boolean hasDestructionAwareBeanPostProcessors() {
0706: return this .hasDestructionAwareBeanPostProcessors;
0707: }
0708:
0709: public void registerScope(String scopeName, Scope scope) {
0710: Assert.notNull(scopeName, "Scope identifier must not be null");
0711: Assert.notNull(scope, "Scope must not be null");
0712: if (SCOPE_SINGLETON.equals(scopeName)
0713: || SCOPE_PROTOTYPE.equals(scopeName)) {
0714: throw new IllegalArgumentException(
0715: "Cannot replace existing scopes 'singleton' and 'prototype'");
0716: }
0717: this .scopes.put(scopeName, scope);
0718: }
0719:
0720: public String[] getRegisteredScopeNames() {
0721: return StringUtils.toStringArray(this .scopes.keySet());
0722: }
0723:
0724: public Scope getRegisteredScope(String scopeName) {
0725: Assert.notNull(scopeName, "Scope identifier must not be null");
0726: return (Scope) this .scopes.get(scopeName);
0727: }
0728:
0729: public void copyConfigurationFrom(
0730: ConfigurableBeanFactory otherFactory) {
0731: Assert.notNull(otherFactory, "BeanFactory must not be null");
0732: setBeanClassLoader(otherFactory.getBeanClassLoader());
0733: setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
0734: if (otherFactory instanceof AbstractBeanFactory) {
0735: AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory;
0736: this .customEditors
0737: .putAll(otherAbstractFactory.customEditors);
0738: this .propertyEditorRegistrars
0739: .addAll(otherAbstractFactory.propertyEditorRegistrars);
0740: this .beanPostProcessors
0741: .addAll(otherAbstractFactory.beanPostProcessors);
0742: this .hasInstantiationAwareBeanPostProcessors = this .hasInstantiationAwareBeanPostProcessors
0743: || otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
0744: this .hasDestructionAwareBeanPostProcessors = this .hasDestructionAwareBeanPostProcessors
0745: || otherAbstractFactory.hasDestructionAwareBeanPostProcessors;
0746: this .scopes.putAll(otherAbstractFactory.scopes);
0747: }
0748: }
0749:
0750: public void registerAlias(String beanName, String alias)
0751: throws BeanDefinitionStoreException {
0752: Assert.hasText(beanName, "'beanName' must not be empty");
0753: Assert.hasText(alias, "'alias' must not be empty");
0754: if (!alias.equals(beanName)) {
0755: // Only actually register the alias if it is not equal to the bean name itself.
0756: if (logger.isDebugEnabled()) {
0757: logger.debug("Registering alias '" + alias
0758: + "' for bean with name '" + beanName + "'");
0759: }
0760: synchronized (this .aliasMap) {
0761: Object registeredName = this .aliasMap.get(alias);
0762: if (registeredName != null
0763: && !registeredName.equals(beanName)) {
0764: throw new BeanDefinitionStoreException(
0765: "Cannot register alias '"
0766: + alias
0767: + "' for bean name '"
0768: + beanName
0769: + "': It's already registered for bean name '"
0770: + registeredName + "'.");
0771: }
0772: this .aliasMap.put(alias, beanName);
0773: }
0774: }
0775: }
0776:
0777: /**
0778: * Callback before prototype creation.
0779: * <p>The default implementation register the prototype as currently in creation.
0780: * @param beanName the name of the prototype about to be created
0781: * @see #isPrototypeCurrentlyInCreation
0782: */
0783: protected void beforePrototypeCreation(String beanName) {
0784: Object curVal = this .prototypesCurrentlyInCreation.get();
0785: if (curVal == null) {
0786: this .prototypesCurrentlyInCreation.set(beanName);
0787: } else if (curVal instanceof String) {
0788: Set beanNameSet = new HashSet(2);
0789: beanNameSet.add(curVal);
0790: beanNameSet.add(beanName);
0791: this .prototypesCurrentlyInCreation.set(beanNameSet);
0792: } else {
0793: Set beanNameSet = (Set) curVal;
0794: beanNameSet.add(beanName);
0795: }
0796: }
0797:
0798: /**
0799: * Callback after prototype creation.
0800: * <p>The default implementation marks the prototype as not in creation anymore.
0801: * @param beanName the name of the prototype that has been created
0802: * @see #isPrototypeCurrentlyInCreation
0803: */
0804: protected void afterPrototypeCreation(String beanName) {
0805: Object curVal = this .prototypesCurrentlyInCreation.get();
0806: if (curVal instanceof String) {
0807: this .prototypesCurrentlyInCreation.set(null);
0808: } else if (curVal instanceof Set) {
0809: Set beanNameSet = (Set) curVal;
0810: beanNameSet.remove(beanName);
0811: if (beanNameSet.isEmpty()) {
0812: this .prototypesCurrentlyInCreation.set(null);
0813: }
0814: }
0815: }
0816:
0817: /**
0818: * Return whether the specified prototype bean is currently in creation
0819: * (within the current thread).
0820: * @param beanName the name of the bean
0821: */
0822: protected final boolean isPrototypeCurrentlyInCreation(
0823: String beanName) {
0824: Object curVal = this .prototypesCurrentlyInCreation.get();
0825: return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set) curVal)
0826: .contains(beanName))));
0827: }
0828:
0829: public boolean isCurrentlyInCreation(String beanName) {
0830: return isSingletonCurrentlyInCreation(beanName)
0831: || isPrototypeCurrentlyInCreation(beanName);
0832: }
0833:
0834: public void destroyBean(String beanName, Object beanInstance) {
0835: destroyBean(beanName, beanInstance,
0836: getMergedBeanDefinition(beanName));
0837: }
0838:
0839: /**
0840: * Destroy the given bean instance (usually a prototype instance
0841: * obtained from this factory) according to the given bean definition.
0842: * @param beanName the name of the bean definition
0843: * @param beanInstance the bean instance to destroy
0844: * @param mbd the merged bean definition
0845: */
0846: protected void destroyBean(String beanName, Object beanInstance,
0847: RootBeanDefinition mbd) {
0848: new DisposableBeanAdapter(beanInstance, beanName, mbd,
0849: getBeanPostProcessors()).destroy();
0850: }
0851:
0852: public void destroyScopedBean(String beanName) {
0853: RootBeanDefinition mbd = getMergedBeanDefinition(beanName);
0854: if (mbd.isSingleton() || mbd.isPrototype()) {
0855: throw new IllegalArgumentException("Bean name '" + beanName
0856: + "' does not correspond to an object in a Scope");
0857: }
0858: String scopeName = mbd.getScope();
0859: Scope scope = (Scope) this .scopes.get(scopeName);
0860: if (scope == null) {
0861: throw new IllegalStateException(
0862: "No Scope registered for scope '" + scopeName + "'");
0863: }
0864: Object bean = scope.remove(beanName);
0865: if (bean != null) {
0866: destroyBean(beanName, bean, mbd);
0867: }
0868: }
0869:
0870: //---------------------------------------------------------------------
0871: // Implementation methods
0872: //---------------------------------------------------------------------
0873:
0874: /**
0875: * Return the bean name, stripping out the factory dereference prefix if necessary,
0876: * and resolving aliases to canonical names.
0877: * @param name the user-specified name
0878: * @return the transformed bean name
0879: */
0880: protected String transformedBeanName(String name) {
0881: String canonicalName = BeanFactoryUtils
0882: .transformedBeanName(name);
0883: // Handle aliasing.
0884: String resolvedName = null;
0885: do {
0886: resolvedName = (String) this .aliasMap.get(canonicalName);
0887: if (resolvedName != null) {
0888: canonicalName = resolvedName;
0889: }
0890: } while (resolvedName != null);
0891: return canonicalName;
0892: }
0893:
0894: /**
0895: * Determine the original bean name, resolving locally defined aliases to canonical names.
0896: * @param name the user-specified name
0897: * @return the original bean name
0898: */
0899: protected String originalBeanName(String name) {
0900: String beanName = transformedBeanName(name);
0901: if (name.startsWith(FACTORY_BEAN_PREFIX)) {
0902: beanName = FACTORY_BEAN_PREFIX + beanName;
0903: }
0904: return beanName;
0905: }
0906:
0907: /**
0908: * Determine whether this given bean name is defines as an alias
0909: * (as opposed to the name of an actual bean definition).
0910: * @param beanName the bean name to check
0911: * @return whether the given name is an alias
0912: */
0913: protected boolean isAlias(String beanName) {
0914: return this .aliasMap.containsKey(beanName);
0915: }
0916:
0917: /**
0918: * Initialize the given BeanWrapper with the custom editors registered
0919: * with this factory. To be called for BeanWrappers that will create
0920: * and populate bean instances.
0921: * <p>The default implementation delegates to <code>registerCustomEditors</code>.
0922: * Can be overridden in subclasses.
0923: * @param bw the BeanWrapper to initialize
0924: * @see #registerCustomEditors
0925: */
0926: protected void initBeanWrapper(BeanWrapper bw) {
0927: registerCustomEditors(bw);
0928: }
0929:
0930: /**
0931: * Initialize the given PropertyEditorRegistry with the custom editors
0932: * registered with this BeanFactory.
0933: * <p>To be called for BeanWrappers that will create and populate bean
0934: * instances, and for SimpleTypeConverter used for constructor argument
0935: * and factory method type conversion.
0936: * @param registry the PropertyEditorRegistry to initialize
0937: */
0938: protected void registerCustomEditors(PropertyEditorRegistry registry) {
0939: PropertyEditorRegistrySupport registrySupport = (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry
0940: : null);
0941: if (registrySupport != null) {
0942: registrySupport.useConfigValueEditors();
0943: }
0944: for (Iterator it = this .propertyEditorRegistrars.iterator(); it
0945: .hasNext();) {
0946: PropertyEditorRegistrar registrar = (PropertyEditorRegistrar) it
0947: .next();
0948: registrar.registerCustomEditors(registry);
0949: }
0950: for (Iterator it = this .customEditors.entrySet().iterator(); it
0951: .hasNext();) {
0952: Map.Entry entry = (Map.Entry) it.next();
0953: Class clazz = (Class) entry.getKey();
0954: PropertyEditor editor = (PropertyEditor) entry.getValue();
0955: // Register the editor as shared instance, if possible,
0956: // to make it clear that it might be used concurrently.
0957: if (registrySupport != null) {
0958: registrySupport.registerSharedEditor(clazz, editor);
0959: } else {
0960: registry.registerCustomEditor(clazz, editor);
0961: }
0962: }
0963: }
0964:
0965: /**
0966: * Return a RootBeanDefinition for the given bean name,
0967: * merging a child bean definition with its parent if necessary.
0968: * @param beanName the name of the bean to retrieve the merged definition for
0969: * @return a (potentially merged) RootBeanDefinition for the given bean
0970: * @throws NoSuchBeanDefinitionException if there is no bean with the given name
0971: * @throws BeanDefinitionStoreException in case of an invalid bean definition
0972: */
0973: public RootBeanDefinition getMergedBeanDefinition(String beanName)
0974: throws BeansException {
0975: return getMergedBeanDefinition(beanName, false);
0976: }
0977:
0978: /**
0979: * Return a RootBeanDefinition, even by traversing parent if the parameter is a
0980: * child definition. Can ask the parent bean factory if not found in this instance.
0981: * @param beanName the name of the bean to retrieve the merged definition for
0982: * @param includingAncestors whether to ask the parent bean factory if not found
0983: * in this instance
0984: * @return a (potentially merged) RootBeanDefinition for the given bean
0985: * @throws NoSuchBeanDefinitionException if there is no bean with the given name
0986: * @throws BeanDefinitionStoreException in case of an invalid bean definition
0987: */
0988: protected RootBeanDefinition getMergedBeanDefinition(
0989: String beanName, boolean includingAncestors)
0990: throws BeansException {
0991:
0992: // Efficiently check whether bean definition exists in this factory.
0993: if (includingAncestors
0994: && !containsBeanDefinition(beanName)
0995: && getParentBeanFactory() instanceof AbstractBeanFactory) {
0996: return ((AbstractBeanFactory) getParentBeanFactory())
0997: .getMergedBeanDefinition(beanName, true);
0998: }
0999:
1000: // Resolve merged bean definition locally.
1001: return getMergedBeanDefinition(beanName,
1002: getBeanDefinition(beanName));
1003: }
1004:
1005: /**
1006: * Return a RootBeanDefinition for the given top-level bean, by merging with
1007: * the parent if the given bean's definition is a child bean definition.
1008: * @param beanName the name of the bean definition
1009: * @param bd the original bean definition (Root/ChildBeanDefinition)
1010: * @return a (potentially merged) RootBeanDefinition for the given bean
1011: * @throws BeanDefinitionStoreException in case of an invalid bean definition
1012: */
1013: protected RootBeanDefinition getMergedBeanDefinition(
1014: String beanName, BeanDefinition bd)
1015: throws BeanDefinitionStoreException {
1016:
1017: return getMergedBeanDefinition(beanName, bd, null);
1018: }
1019:
1020: /**
1021: * Return a RootBeanDefinition for the given bean, by merging with the
1022: * parent if the given bean's definition is a child bean definition.
1023: * @param beanName the name of the bean definition
1024: * @param bd the original bean definition (Root/ChildBeanDefinition)
1025: * @param containingBd the containing bean definition in case of inner bean,
1026: * or <code>null</code> in case of a top-level bean
1027: * @return a (potentially merged) RootBeanDefinition for the given bean
1028: * @throws BeanDefinitionStoreException in case of an invalid bean definition
1029: */
1030: protected RootBeanDefinition getMergedBeanDefinition(
1031: String beanName, BeanDefinition bd,
1032: BeanDefinition containingBd)
1033: throws BeanDefinitionStoreException {
1034:
1035: RootBeanDefinition mbd = null;
1036: // Quick check on the concurrent map first, with minimal locking.
1037: if (containingBd == null) {
1038: mbd = (RootBeanDefinition) this .mergedBeanDefinitions
1039: .get(beanName);
1040: }
1041: if (mbd == null) {
1042:
1043: synchronized (this .mergedBeanDefinitions) {
1044: // Second check with full lock now, to enforce the same merged instance.
1045: if (containingBd == null) {
1046: mbd = (RootBeanDefinition) this .mergedBeanDefinitions
1047: .get(beanName);
1048: }
1049: if (mbd == null) {
1050:
1051: if (bd instanceof RootBeanDefinition) {
1052: // Use copy of given root bean definition.
1053: mbd = new RootBeanDefinition(
1054: (RootBeanDefinition) bd);
1055: }
1056:
1057: else if (bd instanceof ChildBeanDefinition) {
1058: // Child bean definition: needs to be merged with parent.
1059: ChildBeanDefinition cbd = (ChildBeanDefinition) bd;
1060: RootBeanDefinition pbd = null;
1061: try {
1062: String parentBeanName = transformedBeanName(cbd
1063: .getParentName());
1064: if (!beanName.equals(parentBeanName)) {
1065: pbd = getMergedBeanDefinition(
1066: parentBeanName, true);
1067: } else {
1068: if (getParentBeanFactory() instanceof AbstractBeanFactory) {
1069: AbstractBeanFactory parentFactory = (AbstractBeanFactory) getParentBeanFactory();
1070: pbd = parentFactory
1071: .getMergedBeanDefinition(
1072: parentBeanName,
1073: true);
1074: } else {
1075: throw new NoSuchBeanDefinitionException(
1076: cbd.getParentName(),
1077: "Parent name '"
1078: + cbd
1079: .getParentName()
1080: + "' is equal to bean name '"
1081: + beanName
1082: + "': cannot be resolved without an AbstractBeanFactory parent");
1083: }
1084: }
1085: } catch (NoSuchBeanDefinitionException ex) {
1086: throw new BeanDefinitionStoreException(
1087: cbd.getResourceDescription(),
1088: beanName,
1089: "Could not resolve parent bean definition '"
1090: + cbd.getParentName() + "'",
1091: ex);
1092: }
1093:
1094: // Deep copy with overridden values.
1095: mbd = new RootBeanDefinition(pbd);
1096: mbd.overrideFrom(cbd);
1097: }
1098:
1099: else {
1100: throw new BeanDefinitionStoreException(bd
1101: .getResourceDescription(), beanName,
1102: "Definition is neither a RootBeanDefinition nor a ChildBeanDefinition: "
1103: + bd);
1104: }
1105:
1106: // A bean contained in a non-singleton bean cannot be a singleton itself.
1107: // Let's correct this on the fly here, since this might be the result of
1108: // parent-child merging for the outer bean, in which case the original inner bean
1109: // definition will not have inherited the merged outer bean's singleton status.
1110: if (containingBd != null
1111: && !containingBd.isSingleton()
1112: && mbd.isSingleton()) {
1113: mbd.setSingleton(false);
1114: }
1115:
1116: // Only cache the merged bean definition if we're already about to create an
1117: // instance of the bean, or at least have already created an instance before.
1118: if (containingBd == null && isCacheBeanMetadata()
1119: && this .alreadyCreated.contains(beanName)) {
1120: this .mergedBeanDefinitions.put(beanName, mbd);
1121: }
1122: }
1123: }
1124: }
1125:
1126: return mbd;
1127: }
1128:
1129: /**
1130: * Check the given merged bean definition,
1131: * potentially throwing validation exceptions.
1132: * @param mbd the merged bean definition to check
1133: * @param beanName the name of the bean
1134: * @param args the arguments for bean creation, if any
1135: * @throws BeanDefinitionStoreException in case of validation failure
1136: */
1137: protected void checkMergedBeanDefinition(RootBeanDefinition mbd,
1138: String beanName, Object[] args)
1139: throws BeanDefinitionStoreException {
1140:
1141: // check if bean definition is not abstract
1142: if (mbd.isAbstract()) {
1143: throw new BeanIsAbstractException(beanName);
1144: }
1145:
1146: // Check validity of the usage of the args parameter. This can
1147: // only be used for prototypes constructed via a factory method.
1148: if (args != null) {
1149: if (mbd.isSingleton()) {
1150: throw new BeanDefinitionStoreException(
1151: "Cannot specify arguments in the getBean() method when referring to a singleton bean definition");
1152: } else if (mbd.getFactoryMethodName() == null) {
1153: throw new BeanDefinitionStoreException(
1154: "Can only specify arguments in the getBean() method in conjunction with a factory method");
1155: }
1156: }
1157: }
1158:
1159: /**
1160: * Remove the merged bean definition for the specified bean,
1161: * recreating it on next access.
1162: * @param beanName the bean name to clear the merged definition for
1163: */
1164: protected void clearMergedBeanDefinition(String beanName) {
1165: this .mergedBeanDefinitions.remove(beanName);
1166: }
1167:
1168: /**
1169: * Resolve the bean class for the specified bean definition,
1170: * resolving a bean class name into a Class reference (if necessary)
1171: * and storing the resolved Class in the bean definition for further use.
1172: * @param mbd the merged bean definition to determine the class for
1173: * @param beanName the name of the bean (for error handling purposes)
1174: * @return the resolved bean class (or <code>null</code> if none)
1175: * @throws CannotLoadBeanClassException if we failed to load the class
1176: */
1177: protected Class resolveBeanClass(RootBeanDefinition mbd,
1178: String beanName) throws CannotLoadBeanClassException {
1179: if (mbd.hasBeanClass()) {
1180: return mbd.getBeanClass();
1181: }
1182: try {
1183: return mbd.resolveBeanClass(getBeanClassLoader());
1184: } catch (ClassNotFoundException ex) {
1185: throw new CannotLoadBeanClassException(mbd
1186: .getResourceDescription(), beanName, mbd
1187: .getBeanClassName(), ex);
1188: } catch (LinkageError err) {
1189: throw new CannotLoadBeanClassException(mbd
1190: .getResourceDescription(), beanName, mbd
1191: .getBeanClassName(), err);
1192: }
1193: }
1194:
1195: /**
1196: * Check whether the bean class of the given bean definition matches
1197: * the specified target type. Allows for lazy loading of the actual
1198: * bean class, provided that the type match can be determined otherwise.
1199: * <p>The default implementation simply delegates to the standard
1200: * <code>resolveBeanClass</code> method. Subclasses may override this
1201: * to use a different strategy, such as a throwaway class loaer.
1202: * @param beanName the name of the bean (for error handling purposes)
1203: * @param mbd the merged bean definition to determine the class for
1204: * @param targetType the type to match against (never <code>null</code>)
1205: * @return the resolved bean class (or <code>null</code> if none)
1206: * @throws CannotLoadBeanClassException if we failed to load the class
1207: * @see #resolveBeanClass
1208: */
1209: protected boolean isBeanClassMatch(String beanName,
1210: RootBeanDefinition mbd, Class targetType)
1211: throws CannotLoadBeanClassException {
1212:
1213: Class beanClass = resolveBeanClass(mbd, beanName);
1214: return (beanClass != null && targetType
1215: .isAssignableFrom(beanClass));
1216: }
1217:
1218: /**
1219: * Predict the eventual bean type (of the processed bean instance) for the
1220: * specified bean. Called by {@link #getType} and {@link #isTypeMatch}.
1221: * Does not need to handle FactoryBeans specifically, since it is only
1222: * supposed to operate on the raw bean type.
1223: * <p>This implementation is simplistic in that it is not able to
1224: * handle factory methods and InstantiationAwareBeanPostProcessors.
1225: * It only predicts the bean type correctly for a standard bean.
1226: * To be overridden in subclasses, applying more sophisticated type detection.
1227: * @param beanName the name of the bean
1228: * @param mbd the merged bean definition to determine the type for
1229: * @return the type of the bean, or <code>null</code> if not predictable
1230: */
1231: protected Class predictBeanType(String beanName,
1232: RootBeanDefinition mbd) {
1233: if (mbd.getFactoryMethodName() != null) {
1234: return null;
1235: }
1236: return resolveBeanClass(mbd, beanName);
1237: }
1238:
1239: /**
1240: * Determine the bean type for the given FactoryBean definition, as far as possible.
1241: * Only called if there is no singleton instance registered for the target bean already.
1242: * <p>The default implementation creates the FactoryBean via <code>getBean</code>
1243: * to call its <code>getObjectType</code> method. Subclasses are encouraged to optimize
1244: * this, typically by just instantiating the FactoryBean but not populating it yet,
1245: * trying whether its <code>getObjectType</code> method already returns a type.
1246: * If no type found, a full FactoryBean creation as performed by this implementation
1247: * should be used as fallback.
1248: * @param beanName the name of the bean
1249: * @param mbd the merged bean definition for the bean
1250: * @return the type for the bean if determinable, or <code>null</code> else
1251: * @see org.springframework.beans.factory.FactoryBean#getObjectType()
1252: * @see #getBean(String)
1253: */
1254: protected Class getTypeForFactoryBean(String beanName,
1255: RootBeanDefinition mbd) {
1256: if (!mbd.isSingleton()) {
1257: return null;
1258: }
1259: try {
1260: FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX
1261: + beanName);
1262: return getTypeForFactoryBean(factoryBean);
1263: } catch (BeanCreationException ex) {
1264: // Can only happen when getting a FactoryBean.
1265: logger
1266: .debug(
1267: "Ignoring bean creation exception on FactoryBean type check",
1268: ex);
1269: return null;
1270: }
1271: }
1272:
1273: /**
1274: * Determine the type for the given FactoryBean.
1275: * @param factoryBean the FactoryBean instance to check
1276: * @return the FactoryBean's object type,
1277: * or <code>null</code> if the type cannot be determined yet
1278: */
1279: protected Class getTypeForFactoryBean(FactoryBean factoryBean) {
1280: try {
1281: return factoryBean.getObjectType();
1282: } catch (Throwable ex) {
1283: // Thrown from the FactoryBean's getObjectType implementation.
1284: logger
1285: .warn(
1286: "FactoryBean threw exception from getObjectType, despite the contract saying "
1287: + "that it should return null if the type of its object cannot be determined yet",
1288: ex);
1289: return null;
1290: }
1291: }
1292:
1293: /**
1294: * Get the object for the given bean instance, either the bean
1295: * instance itself or its created object in case of a FactoryBean.
1296: * @param beanInstance the shared bean instance
1297: * @param name name that may include factory dereference prefix
1298: * @param mbd the merged bean definition
1299: * @return the object to expose for the bean
1300: */
1301: protected Object getObjectForBeanInstance(Object beanInstance,
1302: String name, RootBeanDefinition mbd) {
1303: // Don't let calling code try to dereference the
1304: // bean factory if the bean isn't a factory.
1305: if (BeanFactoryUtils.isFactoryDereference(name)
1306: && !(beanInstance instanceof FactoryBean)) {
1307: throw new BeanIsNotAFactoryException(
1308: transformedBeanName(name), beanInstance.getClass());
1309: }
1310:
1311: boolean shared = (mbd == null || mbd.isSingleton());
1312: Object object = beanInstance;
1313:
1314: // Now we have the bean instance, which may be a normal bean or a FactoryBean.
1315: // If it's a FactoryBean, we use it to create a bean instance, unless the
1316: // caller actually wants a reference to the factory.
1317: if (beanInstance instanceof FactoryBean) {
1318: if (!BeanFactoryUtils.isFactoryDereference(name)) {
1319: // Return bean instance from factory.
1320: FactoryBean factory = (FactoryBean) beanInstance;
1321: String beanName = transformedBeanName(name);
1322: // Cache object obtained from FactoryBean if it is a singleton.
1323: if (shared && factory.isSingleton()) {
1324: synchronized (getSingletonMutex()) {
1325: object = this .factoryBeanObjectCache
1326: .get(beanName);
1327: if (object == null) {
1328: object = getObjectFromFactoryBean(factory,
1329: beanName, mbd);
1330: this .factoryBeanObjectCache.put(beanName,
1331: object);
1332: }
1333: }
1334: } else {
1335: object = getObjectFromFactoryBean(factory,
1336: beanName, mbd);
1337: }
1338: }
1339: }
1340:
1341: return object;
1342: }
1343:
1344: /**
1345: * Obtain an object to expose from the given FactoryBean.
1346: * @param factory the FactoryBean instance
1347: * @param beanName the name of the bean
1348: * @param mbd the merged bean definition
1349: * @return the object obtained from the FactoryBean
1350: * @throws BeanCreationException if FactoryBean object creation failed
1351: * @see org.springframework.beans.factory.FactoryBean#getObject()
1352: */
1353: private Object getObjectFromFactoryBean(FactoryBean factory,
1354: String beanName, RootBeanDefinition mbd)
1355: throws BeanCreationException {
1356:
1357: Object object;
1358:
1359: try {
1360: object = factory.getObject();
1361: } catch (FactoryBeanNotInitializedException ex) {
1362: throw new BeanCurrentlyInCreationException(beanName, ex
1363: .toString());
1364: } catch (Throwable ex) {
1365: throw new BeanCreationException(beanName,
1366: "FactoryBean threw exception on object creation",
1367: ex);
1368: }
1369:
1370: // Do not accept a null value for a FactoryBean that's not fully
1371: // initialized yet: Many FactoryBeans just return null then.
1372: if (object == null && isSingletonCurrentlyInCreation(beanName)) {
1373: throw new BeanCurrentlyInCreationException(beanName,
1374: "FactoryBean which is currently in creation returned null from getObject");
1375: }
1376:
1377: if (object != null && (mbd == null || !mbd.isSynthetic())) {
1378: try {
1379: object = postProcessObjectFromFactoryBean(object,
1380: beanName);
1381: } catch (Throwable ex) {
1382: throw new BeanCreationException(
1383: mbd.getResourceDescription(),
1384: beanName,
1385: "Post-processing of the FactoryBean's object failed",
1386: ex);
1387: }
1388: }
1389:
1390: return object;
1391: }
1392:
1393: /**
1394: * Post-process the given object that has been obtained from the FactoryBean.
1395: * The resulting object will get exposed for bean references.
1396: * <p>The default implementation simply returns the given object as-is.
1397: * Subclasses may override this, for example, to apply post-processors.
1398: * @param object the object obtained from the FactoryBean.
1399: * @param beanName the name of the bean
1400: * @return the object to expose
1401: * @throws BeansException if any post-processing failed
1402: */
1403: protected Object postProcessObjectFromFactoryBean(Object object,
1404: String beanName) throws BeansException {
1405: return object;
1406: }
1407:
1408: /**
1409: * Determine whether the bean with the given name is a FactoryBean.
1410: * @param name the name of the bean to check
1411: * @return whether the bean is a FactoryBean
1412: * (<code>false</code> means the bean exists but is not a FactoryBean)
1413: * @throws NoSuchBeanDefinitionException if there is no bean with the given name
1414: */
1415: public boolean isFactoryBean(String name)
1416: throws NoSuchBeanDefinitionException {
1417: String beanName = transformedBeanName(name);
1418:
1419: Object beanInstance = getSingleton(beanName);
1420: if (beanInstance != null) {
1421: return (beanInstance instanceof FactoryBean);
1422: }
1423:
1424: // No singleton instance found -> check bean definition.
1425: if (!containsBeanDefinition(beanName)
1426: && getParentBeanFactory() instanceof AbstractBeanFactory) {
1427: // No bean definition found in this factory -> delegate to parent.
1428: return ((AbstractBeanFactory) getParentBeanFactory())
1429: .isFactoryBean(name);
1430: }
1431:
1432: RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
1433: return isBeanClassMatch(beanName, bd, FactoryBean.class);
1434: }
1435:
1436: /**
1437: * Determine whether the given bean name is already in use within this factory,
1438: * that is, whether there is a local bean registered under this name or
1439: * an inner bean created with this name.
1440: * @param beanName the name to check
1441: */
1442: protected boolean isBeanNameInUse(String beanName) {
1443: return containsLocalBean(beanName)
1444: || hasDependentBean(beanName);
1445: }
1446:
1447: /**
1448: * Determine whether the given bean requires destruction on shutdown.
1449: * <p>The default implementation checks the DisposableBean interface as well as
1450: * a specified destroy method and registered DestructionAwareBeanPostProcessors.
1451: * @param bean the bean instance to check
1452: * @param mbd the corresponding bean definition
1453: * @see org.springframework.beans.factory.DisposableBean
1454: * @see AbstractBeanDefinition#getDestroyMethodName()
1455: * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
1456: */
1457: protected boolean requiresDestruction(Object bean,
1458: RootBeanDefinition mbd) {
1459: return (bean instanceof DisposableBean
1460: || mbd.getDestroyMethodName() != null || hasDestructionAwareBeanPostProcessors());
1461: }
1462:
1463: /**
1464: * Add the given bean to the list of disposable beans in this factory,
1465: * registering its DisposableBean interface and/or the given destroy method
1466: * to be called on factory shutdown (if applicable). Only applies to singletons.
1467: * <p>Also registers bean as dependent on other beans, according to the
1468: * "depends-on" configuration in the bean definition.
1469: * @param beanName the name of the bean
1470: * @param bean the bean instance
1471: * @param mbd the bean definition for the bean
1472: * @see RootBeanDefinition#isSingleton
1473: * @see RootBeanDefinition#getDependsOn
1474: * @see #registerDisposableBean
1475: * @see #registerDependentBean
1476: */
1477: protected void registerDisposableBeanIfNecessary(String beanName,
1478: Object bean, RootBeanDefinition mbd) {
1479: if (mbd.isSingleton() && requiresDestruction(bean, mbd)) {
1480: // Register a DisposableBean implementation that performs all destruction
1481: // work for the given bean: DestructionAwareBeanPostProcessors,
1482: // DisposableBean interface, custom destroy method.
1483: registerDisposableBean(beanName, new DisposableBeanAdapter(
1484: bean, beanName, mbd, getBeanPostProcessors()));
1485:
1486: // Register bean as dependent on other beans, if necessary,
1487: // for correct shutdown order.
1488: String[] dependsOn = mbd.getDependsOn();
1489: if (dependsOn != null) {
1490: for (int i = 0; i < dependsOn.length; i++) {
1491: registerDependentBean(dependsOn[i], beanName);
1492: }
1493: }
1494: }
1495: }
1496:
1497: /**
1498: * Overridden to clear the FactoryBean object cache as well.
1499: */
1500: protected void removeSingleton(String beanName) {
1501: super .removeSingleton(beanName);
1502: this .factoryBeanObjectCache.remove(beanName);
1503: }
1504:
1505: //---------------------------------------------------------------------
1506: // Abstract methods to be implemented by subclasses
1507: //---------------------------------------------------------------------
1508:
1509: /**
1510: * Check if this bean factory contains a bean definition with the given name.
1511: * Does not consider any hierarchy this factory may participate in.
1512: * Invoked by <code>containsBean</code> when no cached singleton instance is found.
1513: * <p>Depending on the nature of the concrete bean factory implementation,
1514: * this operation might be expensive (for example, because of directory lookups
1515: * in external registries). However, for listable bean factories, this usually
1516: * just amounts to a local hash lookup: The operation is therefore part of the
1517: * public interface there. The same implementation can serve for both this
1518: * template method and the public interface method in that case.
1519: * @param beanName the name of the bean to look for
1520: * @return if this bean factory contains a bean definition with the given name
1521: * @see #containsBean
1522: * @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition
1523: */
1524: protected abstract boolean containsBeanDefinition(String beanName);
1525:
1526: /**
1527: * Return the bean definition for the given bean name.
1528: * Subclasses should normally implement caching, as this method is invoked
1529: * by this class every time bean definition metadata is needed.
1530: * <p>Depending on the nature of the concrete bean factory implementation,
1531: * this operation might be expensive (for example, because of directory lookups
1532: * in external registries). However, for listable bean factories, this usually
1533: * just amounts to a local hash lookup: The operation is therefore part of the
1534: * public interface there. The same implementation can serve for both this
1535: * template method and the public interface method in that case.
1536: * @param beanName the name of the bean to find a definition for
1537: * @return the BeanDefinition for this prototype name (never <code>null</code>)
1538: * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
1539: * if the bean definition cannot be resolved
1540: * @throws BeansException in case of errors
1541: * @see RootBeanDefinition
1542: * @see ChildBeanDefinition
1543: * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
1544: */
1545: protected abstract BeanDefinition getBeanDefinition(String beanName)
1546: throws BeansException;
1547:
1548: /**
1549: * Create a bean instance for the given bean definition.
1550: * The bean definition will already have been merged with the parent
1551: * definition in case of a child definition.
1552: * <p>All the other methods in this class invoke this method, although
1553: * beans may be cached after being instantiated by this method. All bean
1554: * instantiation within this class is performed by this method.
1555: * @param beanName the name of the bean
1556: * @param mbd the merged bean definition for the bean
1557: * @param args arguments to use if creating a prototype using explicit arguments to a
1558: * static factory method. This parameter must be <code>null</code> except in this case.
1559: * @return a new instance of the bean
1560: * @throws BeanCreationException if the bean could not be created
1561: */
1562: protected abstract Object createBean(String beanName,
1563: RootBeanDefinition mbd, Object[] args)
1564: throws BeanCreationException;
1565:
1566: }
|