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