Package org.springframework.beans.factory.support

Source Code of org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.beans.factory.support;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorUtils;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

/**
* Abstract bean factory superclass that implements default bean creation,
* with the full capabilities specified by the {@link RootBeanDefinition} class.
* Implements the {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
* interface in addition to AbstractBeanFactory's {@link #createBean} method.
*
* <p>Provides bean creation (with constructor resolution), property population,
* wiring (including autowiring), and initialization. Handles runtime bean
* references, resolves managed collections, calls initialization methods, etc.
* Supports autowiring constructors, properties by name, and properties by type.
*
* <p>The main template method to be implemented by subclasses is
* {@link #findAutowireCandidates}, used for autowiring by type. In case of
* a factory which is capable of searching its bean definitions, matching
* beans will typically be implemented through such a search. For other
* factory styles, simplified matching algorithms can be implemented.
*
* <p>Note that this class does <i>not</i> assume or implement bean definition
* registry capabilities. See {@link DefaultListableBeanFactory} for an implementation
* of the {@link org.springframework.beans.factory.ListableBeanFactory} and
* {@link BeanDefinitionRegistry} interfaces, which represent the API and SPI
* view of such a factory, respectively.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rob Harrop
* @author Mark Fisher
* @since 13.02.2004
* @see RootBeanDefinition
* @see DefaultListableBeanFactory
* @see BeanDefinitionRegistry
*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
    implements AutowireCapableBeanFactory {

  private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

  /** Whether to automatically try to resolve circular references between beans */
  private boolean allowCircularReferences = true;

  /**
   * Whether to resort to injecting a raw bean instance in case of circular reference,
   * even if the injected bean eventually got wrapped.
   */
  private boolean allowRawInjectionDespiteWrapping = false;

  /**
   * Dependency types to ignore on dependency check and autowire, as Set of
   * Class objects: for example, String. Default is none.
   */
  private final Set ignoredDependencyTypes = new HashSet();

  /**
   * Dependency interfaces to ignore on dependency check and autowire, as Set of
   * Class objects. By default, only the BeanFactory interface is ignored.
   */
  private final Set ignoredDependencyInterfaces = new HashSet();

  /** Cache of unfinished FactoryBean instances: FactoryBean name --> BeanWrapper */
  private final Map factoryBeanInstanceCache = new HashMap();

  /** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
  private final Map filteredPropertyDescriptorsCache = new HashMap();


  /**
   * Create a new AbstractAutowireCapableBeanFactory.
   */
  public AbstractAutowireCapableBeanFactory() {
    super();
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
  }

  /**
   * Create a new AbstractAutowireCapableBeanFactory with the given parent.
   * @param parentBeanFactory parent bean factory, or <code>null</code> if none
   */
  public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) {
    this();
    setParentBeanFactory(parentBeanFactory);
  }


  /**
   * Set the instantiation strategy to use for creating bean instances.
   * Default is CglibSubclassingInstantiationStrategy.
   * @see CglibSubclassingInstantiationStrategy
   */
  public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
    this.instantiationStrategy = instantiationStrategy;
  }

  /**
   * Return the instantiation strategy to use for creating bean instances.
   */
  protected InstantiationStrategy getInstantiationStrategy() {
    return this.instantiationStrategy;
  }

  /**
   * Set whether to allow circular references between beans - and automatically
   * try to resolve them.
   * <p>Note that circular reference resolution means that one of the involved beans
   * will receive a reference to another bean that is not fully initialized yet.
   * This can lead to subtle and not-so-subtle side effects on initialization;
   * it does work fine for many scenarios, though.
   * <p>Default is "true". Turn this off to throw an exception when encountering
   * a circular reference, disallowing them completely.
   * <p><b>NOTE:</b> It is generally recommended to not rely on circular references
   * between your beans. Refactor your application logic to have the two beans
   * involved delegate to a third bean that encapsulates their common logic.
   */
  public void setAllowCircularReferences(boolean allowCircularReferences) {
    this.allowCircularReferences = allowCircularReferences;
  }

  /**
   * Set whether to allow the raw injection of a bean instance into some other
   * bean's property, despite the injected bean eventually getting wrapped
   * (for example, through AOP auto-proxying).
   * <p>This will only be used as a last resort in case of a circular reference
   * that cannot be resolved otherwise: essentially, preferring a raw instance
   * getting injected over a failure of the entire bean wiring process.
   * <p>Default is "false", as of Spring 2.0. Turn this on to allow for non-wrapped
   * raw beans injected into some of your references, which was Spring 1.2's
   * (arguably unclean) default behavior.
   * <p><b>NOTE:</b> It is generally recommended to not rely on circular references
   * between your beans, in particular with auto-proxying involved.
   * @see #setAllowCircularReferences
   */
  public void setAllowRawInjectionDespiteWrapping(boolean allowRawInjectionDespiteWrapping) {
    this.allowRawInjectionDespiteWrapping = allowRawInjectionDespiteWrapping;
  }

  /**
   * Ignore the given dependency type for autowiring:
   * for example, String. Default is none.
   */
  public void ignoreDependencyType(Class type) {
    this.ignoredDependencyTypes.add(type);
  }

  /**
   * Ignore the given dependency interface for autowiring.
   * <p>This will typically be used by application contexts to register
   * dependencies that are resolved in other ways, like BeanFactory through
   * BeanFactoryAware or ApplicationContext through ApplicationContextAware.
   * <p>By default, only the BeanFactoryAware interface is ignored.
   * For further types to ignore, invoke this method for each type.
   * @see org.springframework.beans.factory.BeanFactoryAware
   * @see org.springframework.context.ApplicationContextAware
   */
  public void ignoreDependencyInterface(Class ifc) {
    this.ignoredDependencyInterfaces.add(ifc);
  }


  public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
    super.copyConfigurationFrom(otherFactory);
    if (otherFactory instanceof AbstractAutowireCapableBeanFactory) {
      AbstractAutowireCapableBeanFactory otherAutowireFactory =
          (AbstractAutowireCapableBeanFactory) otherFactory;
      this.instantiationStrategy = otherAutowireFactory.instantiationStrategy;
      this.allowCircularReferences = otherAutowireFactory.allowCircularReferences;
      this.ignoredDependencyTypes.addAll(otherAutowireFactory.ignoredDependencyTypes);
      this.ignoredDependencyInterfaces.addAll(otherAutowireFactory.ignoredDependencyInterfaces);
    }
  }


  //---------------------------------------------------------------------
  // Implementation of AutowireCapableBeanFactory interface
  //---------------------------------------------------------------------

  public Object createBean(Class beanClass) throws BeansException {
    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd = new RootBeanDefinition(beanClass, false);
    return createBean(beanClass.getName(), bd, null);
  }

  public Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck)
      throws BeansException {

    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    return createBean(beanClass.getName(), bd, null);
  }

  public Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck)
      throws BeansException {

    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    if (bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
      return autowireConstructor(beanClass.getName(), bd, null, null).getWrappedInstance();
    }
    else {
      Object bean = getInstantiationStrategy().instantiate(bd, null, this);
      populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
      return bean;
    }
  }

  public void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
      throws BeansException {

    if (autowireMode == AUTOWIRE_CONSTRUCTOR) {
      throw new IllegalArgumentException("AUTOWIRE_CONSTRUCTOR not supported for existing bean instance");
    }
    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd =
        new RootBeanDefinition(ClassUtils.getUserClass(existingBean), autowireMode, dependencyCheck);
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    populateBean(bd.getBeanClass().getName(), bd, new BeanWrapperImpl(existingBean));
  }

  public void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException {
    BeanDefinition bd = getMergedBeanDefinition(beanName);
    BeanWrapper bw = new BeanWrapperImpl(existingBean);
    initBeanWrapper(bw);
    applyPropertyValues(beanName, bd, bw, bd.getPropertyValues());
  }

  public Object configureBean(Object existingBean, String beanName) throws BeansException {
    BeanDefinition bd = getMergedBeanDefinition(beanName);
    if (!(bd instanceof RootBeanDefinition)) {
      throw new BeanDefinitionStoreException("configureBean only supported for a merged RootBeanDefinition");
    }
    RootBeanDefinition rbd = (RootBeanDefinition) bd;
    BeanWrapper bw = new BeanWrapperImpl(existingBean);
    initBeanWrapper(bw);
    populateBean(beanName, rbd, bw);
    return initializeBean(beanName, existingBean, rbd);
  }

  public Object initializeBean(Object existingBean, String beanName) {
    return initializeBean(beanName, existingBean, null);
  }

  public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {

    Object result = existingBean;
    for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
      BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
      result = beanProcessor.postProcessBeforeInitialization(result, beanName);
    }
    return result;
  }

  public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

    Object result = existingBean;
    for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
      BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
      result = beanProcessor.postProcessAfterInitialization(result, beanName);
    }
    return result;
  }

  public Object resolveDependency(DependencyDescriptor descriptor, String beanName) throws BeansException {
    return resolveDependency(descriptor, beanName, null, null);
  }

  public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
      Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException  {

    Class type = descriptor.getDependencyType();
    if (type.isArray()) {
      Class componentType = type.getComponentType();
      Map matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);
      if (matchingBeans.isEmpty()) {
        if (descriptor.isRequired()) {
          throw new NoSuchBeanDefinitionException(componentType,
              "Unsatisfied dependency of type [" + componentType + "]: expected at least 1 matching bean");
        }
        return null;
      }
      if (autowiredBeanNames != null) {
        autowiredBeanNames.addAll(matchingBeans.keySet());
      }
      TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
      return converter.convertIfNecessary(matchingBeans.values(), type);
    }
    else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
      Class elementType = descriptor.getCollectionType();
      if (elementType == null) {
        if (descriptor.isRequired()) {
          throw new FatalBeanException("No element type declared for collection");
        }
        return null;
      }
      Map matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);
      if (matchingBeans.isEmpty()) {
        if (descriptor.isRequired()) {
          throw new NoSuchBeanDefinitionException(elementType,
              "Unsatisfied dependency of type [" + elementType.getName() + "]: expected at least 1 matching bean");
        }
        return null;
      }
      if (autowiredBeanNames != null) {
        autowiredBeanNames.addAll(matchingBeans.keySet());
      }
      TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
      return converter.convertIfNecessary(matchingBeans.values(), type);
    }
    else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
      Class keyType = descriptor.getMapKeyType();
      if (keyType == null || !String.class.isAssignableFrom(keyType)) {
        if (descriptor.isRequired()) {
          throw new FatalBeanException("Map key type must be assignable to [" + String.class.getName() + "]");
        }
        return null;
      }
      Class valueType = descriptor.getMapValueType();
      if (valueType == null) {
        if (descriptor.isRequired()) {
          throw new FatalBeanException("No value type declared for map");
        }
        return null;
      }
      Map matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
      if (matchingBeans.isEmpty()) {
        if (descriptor.isRequired()) {
          throw new NoSuchBeanDefinitionException(valueType,
              "Unsatisfied dependency of type [" + valueType.getName() + "]: expected at least 1 matching bean");
        }
        return null;
      }
      if (autowiredBeanNames != null) {
        autowiredBeanNames.addAll(matchingBeans.keySet());
      }
      return matchingBeans;
    }
    else {
      Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
      if (matchingBeans.isEmpty()) {
        if (descriptor.isRequired()) {
          throw new NoSuchBeanDefinitionException(type,
              "Unsatisfied dependency of type [" + type + "]: expected at least 1 matching bean");
        }
        return null;
      }
      if (matchingBeans.size() > 1) {
        String primaryBeanName = determinePrimaryCandidate(matchingBeans, type);
        if (primaryBeanName == null) {
          throw new NoSuchBeanDefinitionException(type,
              "expected single matching bean but found " + matchingBeans.size() + ": " + matchingBeans.keySet());
        }
        if (autowiredBeanNames != null) {
          autowiredBeanNames.add(primaryBeanName);
        }
        return matchingBeans.get(primaryBeanName);
      }
      // We have exactly one match.
      Map.Entry entry = (Map.Entry) matchingBeans.entrySet().iterator().next();
      if (autowiredBeanNames != null) {
        autowiredBeanNames.add(entry.getKey());
      }
      return entry.getValue();
    }
  }


  //---------------------------------------------------------------------
  // Implementation of relevant AbstractBeanFactory template methods
  //---------------------------------------------------------------------

  /**
   * Central method of this class: creates a bean instance,
   * populates the bean instance, applies post-processors, etc.
   * @see #doCreateBean
   */
  protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
      throws BeanCreationException {

    return AccessController.doPrivileged(new PrivilegedAction() {
      public Object run() {
        if (logger.isDebugEnabled()) {
          logger.debug("Creating instance of bean '" + beanName + "' with merged definition [" + mbd + "]");
        }

        // Make sure bean class is actually resolved at this point.
        resolveBeanClass(mbd, beanName);

        // Prepare method overrides.
        try {
          mbd.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
          throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
              beanName, "Validation of method overrides failed", ex);
        }

        try {
          // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
          Object bean = resolveBeforeInstantiation(beanName, mbd);
          if (bean != null) {
            return bean;
          }
        }
        catch (Throwable ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
              "BeanPostProcessor before instantiation of bean failed", ex);
        }

        return doCreateBean(beanName, mbd, args);
      }
    });
  }

  /**
   * Actually create the specified bean. Pre-creation processing has already happened
   * at this point, e.g. checking <code>postProcessBeforeInstantiation</code> callbacks.
   * <p>Differentiates between default bean instantiation, use of a
   * factory method, and autowiring a constructor.
   * @param beanName the name of the bean
   * @param mbd the merged bean definition for the bean
   * @param args arguments to use if creating a prototype using explicit arguments to a
   * static factory method. This parameter must be <code>null</code> except in this case.
   * @return a new instance of the bean
   * @throws BeanCreationException if the bean could not be created
   * @see #instantiateBean
   * @see #instantiateUsingFactoryMethod
   * @see #autowireConstructor
   */
  protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
      synchronized (getSingletonMutex()) {
        instanceWrapper = (BeanWrapper) this.factoryBeanInstanceCache.remove(beanName);
      }
    }
    if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

    // Allow post-processors to modify the merged bean definition.
    if (!mbd.postProcessed) {
      applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
      mbd.postProcessed = true;
    }

    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    if (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName)) {
      if (logger.isDebugEnabled()) {
        logger.debug("Eagerly caching bean '" + beanName +
            "' to allow for resolving potential circular references");
      }
      addSingleton(beanName, bean);
    }

    // Initialize the bean instance.
    Object originalBean = bean;
    try {
      populateBean(beanName, mbd, instanceWrapper);
      bean = initializeBean(beanName, bean, mbd);
    }
    catch (Throwable ex) {
      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
      }
      else {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
      }
    }

    if (!this.allowRawInjectionDespiteWrapping && originalBean != bean &&
        mbd.isSingleton() && hasDependentBean(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName,
          "Bean with name '" + beanName + "' has been injected into other beans [" +
          StringUtils.arrayToCommaDelimitedString(getDependentBeans(beanName)) +
          "] in its raw version as part of a circular reference, but has eventually " +
          "been wrapped (for example as part of auto-proxy creation). " +
          "This means that said other beans do not use the final version of the bean. " +
          "This is often the result of over-eager type matching - consider using " +
          "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
    }

    // Register bean as disposable.
    registerDisposableBeanIfNecessary(beanName, originalBean, mbd);

    return bean;
  }

  /**
   * Predict the eventual bean type for the given bean.
   * @param beanName the name of the bean
   * @param mbd the merged bean definition to determine the type for
   * @return the type of the bean, or <code>null</code> if not predictable
   */
  protected Class predictBeanType(String beanName, RootBeanDefinition mbd, boolean typeMatchOnly) {
    Class beanClass = null;
    if (mbd.getFactoryMethodName() != null) {
      beanClass = getTypeForFactoryMethod(beanName, mbd, typeMatchOnly);
    }
    else {
      beanClass = resolveBeanClass(mbd, beanName, typeMatchOnly);
    }
    // Apply SmartInstantiationAwareBeanPostProcessors to predict the
    // eventual type after a before-instantiation shortcut.
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext(); ) {
        BeanPostProcessor bp = (BeanPostProcessor) it.next();
        if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
          SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
          Class processedType = ibp.predictBeanType(beanClass, beanName);
          if (processedType != null) {
            return processedType;
          }
        }
      }
    }
    return beanClass;
  }

  /**
   * Determine the bean type for the given bean definition which is based on
   * a factory method. Only called if there is no singleton instance registered
   * for the target bean already.
   * <p>This implementation determines the type matching {@link #createBean}'s
   * different creation strategies. As far as possible, we'll perform static
   * type checking to avoid creation of the target bean.
   * @param beanName the name of the bean (for error handling purposes)
   * @param mbd the merged bean definition for the bean
   * @param typeMatchOnly whether the returned {@link Class} is only used
   * for internal type matching purposes (that is, never exposed to application code)
   * @return the type for the bean if determinable, or <code>null</code> else
   * @see #createBean
   */
  protected Class getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, boolean typeMatchOnly) {
    Class factoryClass = null;
    boolean isStatic = true;

    if (mbd.getFactoryBeanName() != null) {
      // Check declared factory method return type on factory class.
      factoryClass = getType(mbd.getFactoryBeanName());
      isStatic = false;
    }
    else {
      // Check declared factory method return type on bean class.
      factoryClass = resolveBeanClass(mbd, beanName, typeMatchOnly);
    }

    if (factoryClass == null) {
      return null;
    }

    // If all factory methods have the same return type, return that type.
    // Can't clearly figure out exact method due to type converting / autowiring!
    int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
    Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
    Set returnTypes = new HashSet(1);
    for (int i = 0; i < candidates.length; i++) {
      Method factoryMethod = candidates[i];
      if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
          factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
          factoryMethod.getParameterTypes().length >= minNrOfArgs) {
        returnTypes.add(factoryMethod.getReturnType());
      }
    }

    if (returnTypes.size() == 1) {
      // Clear return type found: all factory methods return same type.
      return (Class) returnTypes.iterator().next();
    }
    else {
      // Ambiguous return types found: return null to indicate "not determinable".
      return null;
    }
  }

  /**
   * This implementation checks the FactoryBean's <code>getObjectType</code> method
   * on a plain instance of the FactoryBean, without bean properties applied yet.
   * If this doesn't return a type yet, a full creation of the FactoryBean is
   * used as fallback (through delegation to the superclass's implementation).
   * <p>The shortcut check for a FactoryBean is only applied in case of a singleton
   * FactoryBean. If the FactoryBean instance itself is not kept as singleton,
   * it will be fully created to check the type of its exposed object.
   */
  protected Class getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
    FactoryBean fb = (mbd.isSingleton() ?
        getSingletonFactoryBeanForTypeCheck(beanName, mbd) :
        getNonSingletonFactoryBeanForTypeCheck(beanName, mbd));

    if (fb != null) {
      // Try to obtain the FactoryBean's object type from this early stage of the instance.
      Class objectType = getTypeForFactoryBean(fb);
      if (objectType != null) {
        return objectType;
      }
    }

    // No type found - fall back to full creation of the FactoryBean instance.
    return super.getTypeForFactoryBean(beanName, mbd);
  }


  //---------------------------------------------------------------------
  // Implementation methods
  //---------------------------------------------------------------------

  /**
   * Obtain a "shortcut" singleton FactoryBean instance to use for a
   * <code>getObjectType()</code> call, without full initialization
   * of the FactoryBean.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @return the FactoryBean instance, or <code>null</code> to indicate
   * that we couldn't obtain a shortcut FactoryBean instance
   */
  private FactoryBean getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
    synchronized (getSingletonMutex()) {
      BeanWrapper bw = (BeanWrapper) this.factoryBeanInstanceCache.get(beanName);
      if (bw != null) {
        return (FactoryBean) bw.getWrappedInstance();
      }
      if (isSingletonCurrentlyInCreation(beanName)) {
        return null;
      }
      Object instance = null;
      try {
        // Mark this bean as currently in creation, even if just partially.
        beforeSingletonCreation(beanName);
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        instance = resolveBeforeInstantiation(beanName, mbd);
        if (instance == null) {
          bw = createBeanInstance(beanName, mbd, null);
          instance = bw.getWrappedInstance();
        }
      }
      finally {
        // Finished partial creation of this bean.
        afterSingletonCreation(beanName);
      }
      if (!(instance instanceof FactoryBean)) {
        throw new BeanCreationException(beanName,
            "Bean instance of type [" + instance.getClass() + "] is not a FactoryBean");
      }
      if (bw != null) {
        this.factoryBeanInstanceCache.put(beanName, bw);
      }
      return (FactoryBean) instance;
    }
  }

  /**
   * Obtain a "shortcut" non-singleton FactoryBean instance to use for a
   * <code>getObjectType()</code> call, without full initialization
   * of the FactoryBean.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @return the FactoryBean instance, or <code>null</code> to indicate
   * that we couldn't obtain a shortcut FactoryBean instance
   */
  private FactoryBean getNonSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
    if (isPrototypeCurrentlyInCreation(beanName)) {
      return null;
    }
    Object instance = null;
    try {
      // Mark this bean as currently in creation, even if just partially.
      beforePrototypeCreation(beanName);
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      instance = resolveBeforeInstantiation(beanName, mbd);
      if (instance == null) {
        BeanWrapper bw = createBeanInstance(beanName, mbd, null);
        instance = bw.getWrappedInstance();
      }
    }
    finally {
      // Finished partial creation of this bean.
      afterPrototypeCreation(beanName);
    }
    if (!(instance instanceof FactoryBean)) {
      throw new BeanCreationException(beanName,
          "Bean instance of type [" + instance.getClass() + "] is not a FactoryBean");
    }
    return (FactoryBean) instance;
  }

  /**
   * Apply MergedBeanDefinitionPostProcessors to the specified bean definition,
   * invoking their <code>postProcessMergedBeanDefinition</code> methods.
   * @param mbd the merged bean definition for the bean
   * @param beanType the actual type of the managed bean instance
   * @param beanName the name of the bean
   * @throws BeansException if any post-processing failed
   * @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
   */
  protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName)
      throws BeansException {

    for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
      BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
      if (beanProcessor instanceof MergedBeanDefinitionPostProcessor) {
        MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) beanProcessor;
        bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
    }
  }

  /**
   * Apply before-instantiation post-processors, resolving whether there is a
   * before-instantiation shortcut for the specified bean.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @return the shortcut-determined bean instance, or <code>null</code> if none
   */
  protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
        if (bean != null) {
          bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
      }
      mbd.beforeInstantiationResolved = Boolean.valueOf(bean != null);
    }
    return bean;
  }

  /**
   * Apply InstantiationAwareBeanPostProcessors to the specified bean definition
   * (by class and name), invoking their <code>postProcessBeforeInstantiation</code> methods.
   * <p>Any returned object will be used as the bean instead of actually instantiating
   * the target bean. A <code>null</code> return value from the post-processor will
   * result in the target bean being instantiated.
   * @param beanClass the class of the bean to be instantiated
   * @param beanName the name of the bean
   * @return the bean object to use instead of a default instance of the target bean, or <code>null</code>
   * @throws BeansException if any post-processing failed
   * @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
   */
  protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
      throws BeansException {

    for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
      BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
      if (beanProcessor instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) beanProcessor;
        Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
        if (result != null) {
          return result;
        }
      }
    }
    return null;
  }

  /**
   * Create a new instance for the specified bean, using an appropriate instantiation strategy:
   * factory method, constructor autowiring, or simple instantiation.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @param args arguments to use if creating a prototype using explicit arguments to a
   * static factory method. It is invalid to use a non-null args value in any other case.
   * @return BeanWrapper for the new instance
   * @see #instantiateUsingFactoryMethod
   * @see #autowireConstructor
   * @see #instantiateBean
   */
  protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    if (mbd.getFactoryMethodName() != null)  {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    if (mbd.resolvedConstructorOrFactoryMethod != null) {
      if (mbd.constructorArgumentsResolved) {
        return autowireConstructor(beanName, mbd, null, args);
      }
      else {
        return instantiateBean(beanName, mbd);
      }
    }

    // Need to determine the constructor...
    Constructor[] ctors = determineConstructorsFromBeanPostProcessors(mbd.getBeanClass(), beanName);
    if (ctors != null ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      return autowireConstructor(beanName, mbd, ctors, args);
    }

    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd);
  }

  /**
   * Determine candidate constructors to use for the given bean, checking all registered
   * {@link SmartInstantiationAwareBeanPostProcessor SmartInstantiationAwareBeanPostProcessors}.
   * @param beanClass the raw class of the bean
   * @param beanName the name of the bean
   * @return the candidate constructors, or <code>null</code> if none specified
   * @throws org.springframework.beans.BeansException in case of errors
   * @see org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
   */
  protected Constructor[] determineConstructorsFromBeanPostProcessors(Class beanClass, String beanName)
      throws BeansException {

    if (hasInstantiationAwareBeanPostProcessors()) {
      for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
        BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
        if (beanProcessor instanceof SmartInstantiationAwareBeanPostProcessor) {
          SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) beanProcessor;
          Constructor[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
          if (ctors != null) {
            return ctors;
          }
        }
      }
    }
    return null;
  }

  /**
   * Instantiate the given bean using its default constructor.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @return BeanWrapper for the new instance
   */
  protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
    try {
      Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
    }
    catch (Throwable ex) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
  }

  /**
   * Instantiate the bean using a named factory method. The method may be static, if the
   * mbd parameter specifies a class, rather than a factoryBean, or an instance variable
   * on a factory object itself configured using Dependency Injection.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @param explicitArgs argument values passed in programmatically via the getBean method,
   * or <code>null</code> if none (-> use constructor argument values from bean definition)
   * @return BeanWrapper for the new instance
   * @see #getBean(String, Object[])
   */
  protected BeanWrapper instantiateUsingFactoryMethod(
      String beanName, RootBeanDefinition mbd, Object[] explicitArgs) {

    ConstructorResolver constructorResolver = new ConstructorResolverAdapter();
    return constructorResolver.instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
  }

  /**
   * "autowire constructor" (with constructor arguments by type) behavior.
   * Also applied if explicit constructor argument values are specified,
   * matching all remaining arguments with beans from the bean factory.
   * <p>This corresponds to constructor injection: In this mode, a Spring
   * bean factory is able to host components that expect constructor-based
   * dependency resolution.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @param ctors the chosen candidate constructors
   * @param explicitArgs argument values passed in programmatically via the getBean method,
   * or <code>null</code> if none (-> use constructor argument values from bean definition)
   * @return BeanWrapper for the new instance
   */
  protected BeanWrapper autowireConstructor(
      String beanName, RootBeanDefinition mbd, Constructor[] ctors, Object[] explicitArgs) {

    ConstructorResolver constructorResolver = new ConstructorResolverAdapter();
    return constructorResolver.autowireConstructor(beanName, mbd, ctors, explicitArgs);
  }

  /**
   * Populate the bean instance in the given BeanWrapper with the property values
   * from the bean definition.
   * @param beanName the name of the bean
   * @param mbd the bean definition for the bean
   * @param bw BeanWrapper with bean instance
   */
  protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    boolean continueWithPropertyPopulation = true;

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext(); ) {
        BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
        if (beanProcessor instanceof InstantiationAwareBeanPostProcessor) {
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) beanProcessor;
          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
          }
        }
      }
    }

    if (!continueWithPropertyPopulation) {
      return;
    }

    PropertyValues pvs = mbd.getPropertyValues();

    if (bw == null) {
      if (!pvs.isEmpty()) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
        // Skip property population phase for null instance.
        return;
      }
    }

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

      // Add property values based on autowire by name if applicable.
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
      }

      // Add property values based on autowire by type if applicable.
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
      }

      pvs = newPvs;
    }

    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

    if (hasInstAwareBpps || needsDepCheck) {
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
      if (hasInstAwareBpps) {
        for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext(); ) {
          BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
          if (beanProcessor instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) beanProcessor;
            pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvs == null) {
              return;
            }
          }
        }
      }
      if (needsDepCheck) {
        checkDependencies(beanName, mbd, filteredPds, pvs);
      }
    }

    applyPropertyValues(beanName, mbd, bw, pvs);
  }

  /**
   * Fill in any missing property values with references to
   * other beans in this factory if autowire is set to "byName".
   * @param beanName the name of the bean we're wiring up.
   * Useful for debugging messages; not used functionally.
   * @param mbd bean definition to update through autowiring
   * @param bw BeanWrapper from which we can obtain information about the bean
   * @param pvs the PropertyValues to register wired objects with
   */
  protected void autowireByName(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (int i = 0; i < propertyNames.length; i++) {
      String propertyName = propertyNames[i];
      if (containsBean(propertyName)) {
        Object bean = getBean(propertyName);
        pvs.addPropertyValue(propertyName, bean);
        registerDependentBean(propertyName, beanName);
        if (logger.isDebugEnabled()) {
          logger.debug("Added autowiring by name from bean name '" + beanName +
            "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
        }
      }
      else {
        if (logger.isTraceEnabled()) {
          logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
              "' by name: no matching bean found");
        }
      }
    }
  }

  /**
   * Abstract method defining "autowire by type" (bean properties by type) behavior.
   * <p>This is like PicoContainer default, in which there must be exactly one bean
   * of the property type in the bean factory. This makes bean factories simple to
   * configure for small namespaces, but doesn't work as well as standard Spring
   * behavior for bigger applications.
   * @param beanName the name of the bean to autowire by type
   * @param mbd the merged bean definition to update through autowiring
   * @param bw BeanWrapper from which we can obtain information about the bean
   * @param pvs the PropertyValues to register wired objects with
   */
  protected void autowireByType(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
      converter = bw;
    }
    Set autowiredBeanNames = new LinkedHashSet(4);
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (int i = 0; i < propertyNames.length; i++) {
      String propertyName = propertyNames[i];
      try {
        PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
        Object autowiredArgument = resolveDependency(
            new DependencyDescriptor(new MethodParameter(pd.getWriteMethod(), 0), false),
            beanName, autowiredBeanNames, converter);
        if (autowiredArgument != null) {
          pvs.addPropertyValue(propertyName, autowiredArgument);
        }
        for (Iterator it = autowiredBeanNames.iterator(); it.hasNext();) {
          String autowiredBeanName = (String) it.next();
          registerDependentBean(autowiredBeanName, beanName);
          if (logger.isDebugEnabled()) {
            logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
                propertyName + "' to bean named '" + autowiredBeanName + "'");
          }
        }
        autowiredBeanNames.clear();
      }
      catch (BeansException ex) {
        throw new UnsatisfiedDependencyException(
            mbd.getResourceDescription(), beanName, propertyName, ex.getMessage());
      }
    }
  }


  /**
   * Return an array of non-simple bean properties that are unsatisfied.
   * These are probably unsatisfied references to other beans in the
   * factory. Does not include simple properties like primitives or Strings.
   * @param mbd the merged bean definition the bean was created with
   * @param bw the BeanWrapper the bean was created with
   * @return an array of bean property names
   * @see org.springframework.beans.BeanUtils#isSimpleProperty
   */
  protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
    Set result = new TreeSet();
    PropertyValues pvs = mbd.getPropertyValues();
    PropertyDescriptor[] pds = bw.getPropertyDescriptors();
    for (int i = 0; i < pds.length; i++) {
      if (pds[i].getWriteMethod() != null && !isExcludedFromDependencyCheck(pds[i]) &&
          !pvs.contains(pds[i].getName()) && !BeanUtils.isSimpleProperty(pds[i].getPropertyType())) {
        result.add(pds[i].getName());
      }
    }
    return StringUtils.toStringArray(result);
  }

  /**
   * Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
   * excluding ignored dependency types or properties defined on ignored
   * dependency interfaces.
   * @param bw the BeanWrapper the bean was created with
   * @return the filtered PropertyDescriptors
   * @see #isExcludedFromDependencyCheck
   */
  protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
    synchronized (this.filteredPropertyDescriptorsCache) {
      PropertyDescriptor[] filtered = (PropertyDescriptor[])
          this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
      if (filtered == null) {
        List pds = new LinkedList(Arrays.asList(bw.getPropertyDescriptors()));
        for (Iterator it = pds.iterator(); it.hasNext();) {
          PropertyDescriptor pd = (PropertyDescriptor) it.next();
          if (isExcludedFromDependencyCheck(pd)) {
            it.remove();
          }
        }
        filtered = (PropertyDescriptor[]) pds.toArray(new PropertyDescriptor[pds.size()]);
        this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
      }
      return filtered;
    }
  }

  /**
   * Determine whether the given bean property is excluded from dependency checks.
   * <p>This implementation excludes properties defined by CGLIB and
   * properties whose type matches an ignored dependency type or which
   * are defined by an ignored dependency interface.
   * @param pd the PropertyDescriptor of the bean property
   * @return whether the bean property is excluded
   * @see #ignoreDependencyType(Class)
   * @see #ignoreDependencyInterface(Class)
   */
  protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
    return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||
        this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||
        AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
  }

  /**
   * Perform a dependency check that all properties exposed have been set,
   * if desired. Dependency checks can be objects (collaborating beans),
   * simple (primitives and String), or all (both).
   * @param beanName the name of the bean
   * @param mbd the merged bean definition the bean was created with
   * @param pds the relevant property descriptors for the target bean
   * @param pvs the property values to be applied to the bean
   * @see #isExcludedFromDependencyCheck(java.beans.PropertyDescriptor)
   */
  protected void checkDependencies(
      String beanName, AbstractBeanDefinition mbd, PropertyDescriptor[] pds, PropertyValues pvs)
      throws UnsatisfiedDependencyException {

    int dependencyCheck = mbd.getDependencyCheck();
    for (int i = 0; i < pds.length; i++) {
      if (pds[i].getWriteMethod() != null && !pvs.contains(pds[i].getName())) {
        boolean isSimple = BeanUtils.isSimpleProperty(pds[i].getPropertyType());
        boolean unsatisfied = (dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_ALL) ||
          (isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_SIMPLE) ||
          (!isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
        if (unsatisfied) {
          throw new UnsatisfiedDependencyException(
              mbd.getResourceDescription(), beanName, pds[i].getName(),
              "Set this property value or disable dependency checking for this bean.");
        }
      }
    }
  }

  /**
   * Apply the given property values, resolving any runtime references
   * to other beans in this bean factory. Must use deep copy, so we
   * don't permanently modify this property.
   * @param beanName the bean name passed for better exception information
   * @param mbd the merged bean definition
   * @param bw the BeanWrapper wrapping the target object
   * @param pvs the new property values
   */
  protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    if (pvs == null || pvs.isEmpty()) {
      return;
    }

    MutablePropertyValues mpvs = null;
    List original = null;

    if (pvs instanceof MutablePropertyValues) {
      mpvs = (MutablePropertyValues) pvs;
      if (mpvs.isConverted()) {
        // Shortcut: use the pre-converted values as-is.
        try {
          bw.setPropertyValues(mpvs);
          return;
        }
        catch (BeansException ex) {
          throw new BeanCreationException(
              mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
      }
      original = mpvs.getPropertyValueList();
    }
    else {
      original = Arrays.asList(pvs.getPropertyValues());
    }

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
      converter = bw;
    }
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

    // Create a deep copy, resolving any references for values.
    List deepCopy = new ArrayList(original.size());
    boolean resolveNecessary = false;
    for (Iterator it = original.iterator(); it.hasNext();) {
      PropertyValue pv = (PropertyValue) it.next();
      if (pv.isConverted()) {
        deepCopy.add(pv);
      }
      else {
        String propertyName = pv.getName();
        Object originalValue = pv.getValue();
        Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
        // Possibly store converted value in merged bean definition,
        // in order to avoid re-conversion for every created bean instance.
        if (resolvedValue == originalValue) {
          if (!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName)) {
            pv.setConvertedValue(convertForProperty(resolvedValue, propertyName, bw, converter));
          }
          deepCopy.add(pv);
        }
        else if (originalValue instanceof TypedStringValue &&
            !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName)) {
          pv.setConvertedValue(convertForProperty(resolvedValue, propertyName, bw, converter));
          deepCopy.add(pv);
        }
        else {
          resolveNecessary = true;
          deepCopy.add(new PropertyValue(pv, resolvedValue));
        }
      }
    }
    if (mpvs != null && !resolveNecessary) {
      mpvs.setConverted();
    }

    // Set our (possibly massaged) deep copy.
    try {
      bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    }
    catch (BeansException ex) {
      throw new BeanCreationException(
          mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    }
  }

  /**
   * Convert the given value for the specified target property.
   */
  private Object convertForProperty(Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
    if (converter instanceof BeanWrapperImpl) {
      return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
    }
    else {
      PropertyDescriptor descriptor = bw.getPropertyDescriptor(propertyName);
      return converter.convertIfNecessary(
          value, descriptor.getPropertyType(), new MethodParameter(descriptor.getWriteMethod(), 0));
    }
  }


  /**
   * Initialize the given bean instance, applying factory callbacks
   * as well as init methods and bean post processors.
   * <p>Called from {@link #createBean} for traditionally defined beans,
   * and from {@link #initializeBean} for existing bean instances.
   * @param beanName the bean name in the factory (for debugging purposes)
   * @param bean the new bean instance we may need to initialize
   * @param mbd the bean definition that the bean was created with
   * (can also be <code>null</code>, if given an existing bean instance)
   * @return the initialized bean instance (potentially wrapped)
   * @see BeanNameAware
   * @see BeanClassLoaderAware
   * @see BeanFactoryAware
   * @see #applyBeanPostProcessorsBeforeInitialization
   * @see #invokeInitMethods
   * @see #applyBeanPostProcessorsAfterInitialization
   */
  protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
    if (bean instanceof BeanNameAware) {
      ((BeanNameAware) bean).setBeanName(beanName);
    }

    if (bean instanceof BeanClassLoaderAware) {
      ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
    }

    if (bean instanceof BeanFactoryAware) {
      ((BeanFactoryAware) bean).setBeanFactory(this);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
      invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
      throw new BeanCreationException(
          (mbd != null ? mbd.getResourceDescription() : null),
          beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
  }

  /**
   * Give a bean a chance to react now all its properties are set,
   * and a chance to know about its owning bean factory (this object).
   * This means checking whether the bean implements InitializingBean or defines
   * a custom init method, and invoking the necessary callback(s) if it does.
   * @param beanName the bean name in the factory (for debugging purposes)
   * @param bean the new bean instance we may need to initialize
   * @param mbd the merged bean definition that the bean was created with
   * (can also be <code>null</code>, if given an existing bean instance)
   * @throws Throwable if thrown by init methods or by the invocation process
   * @see #invokeCustomInitMethod
   */
  protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd)
      throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      ((InitializingBean) bean).afterPropertiesSet();
    }

    String initMethodName = (mbd != null ? mbd.getInitMethodName() : null);
    if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
        !mbd.isExternallyManagedInitMethod(initMethodName)) {
      invokeCustomInitMethod(beanName, bean, initMethodName, mbd.isEnforceInitMethod());
    }
  }

  /**
   * Invoke the specified custom init method on the given bean.
   * Called by invokeInitMethods.
   * <p>Can be overridden in subclasses for custom resolution of init
   * methods with arguments.
   * @param beanName the bean name in the factory (for debugging purposes)
   * @param bean the new bean instance we may need to initialize
   * @param initMethodName the name of the custom init method
   * @param enforceInitMethod indicates whether the defined init method needs to exist
   * @see #invokeInitMethods
   */
  protected void invokeCustomInitMethod(
      String beanName, Object bean, String initMethodName, boolean enforceInitMethod) throws Throwable {

    Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null);
    if (initMethod == null) {
      if (enforceInitMethod) {
        throw new NoSuchMethodException("Couldn't find an init method named '" + initMethodName +
            "' on bean with name '" + beanName + "'");
      }
      else {
        // Ignore non-existent default lifecycle methods.
        return;
      }
    }
    ReflectionUtils.makeAccessible(initMethod);
    try {
      initMethod.invoke(bean, (Object[]) null);
    }
    catch (InvocationTargetException ex) {
      throw ex.getTargetException();
    }
  }


  /**
   * Applies the <code>postProcessAfterInitialization</code> callback of all
   * registered BeanPostProcessors, giving them a chance to post-process the
   * object obtained from FactoryBeans (for example, to auto-proxy them).
   * @see #applyBeanPostProcessorsAfterInitialization
   */
  protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
  }

  /**
   * Overridden to clear FactoryBean instance cache as well.
   */
  protected void removeSingleton(String beanName) {
    super.removeSingleton(beanName);
    this.factoryBeanInstanceCache.remove(beanName);
  }


  //---------------------------------------------------------------------
  // Template methods to be implemented by subclasses
  //---------------------------------------------------------------------

  /**
   * Find bean instances that match the required type.
   * Called during autowiring for the specified bean.
   * <p>If a subclass cannot obtain information about bean names by type,
   * a corresponding exception should be thrown.
   * @param beanName the name of the bean that is about to be wired
   * @param requiredType the actual type of bean to look for
   * (may be an array component type or collection element type)
   * @param descriptor the descriptor of the dependency to resolve
   * @return a Map of candidate names and candidate instances that match
   * the required type (never <code>null</code>)
   * @throws BeansException in case of errors
   * @see #autowireByType
   * @see #autowireConstructor
   */
  protected abstract Map findAutowireCandidates(
      String beanName, Class requiredType, DependencyDescriptor descriptor)
      throws BeansException;

  protected abstract String determinePrimaryCandidate(Map matchingBeans, Class type);


  //---------------------------------------------------------------------
  // Inner classes that serve as internal helpers
  //---------------------------------------------------------------------

  /**
   * Subclass of ConstructorResolver that delegates to surrounding
   * AbstractAutowireCapableBeanFactory facilities.
   */
  private class ConstructorResolverAdapter extends ConstructorResolver {

    public ConstructorResolverAdapter() {
      super(AbstractAutowireCapableBeanFactory.this, getInstantiationStrategy(), getCustomTypeConverter());
    }

    protected Object resolveAutowiredArgument(
        MethodParameter param, String beanName, Set autowiredBeanNames, TypeConverter typeConverter) {
      return resolveDependency(new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
    }
  }

}
TOP

Related Classes of org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.