org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory Maven / Gradle / Ivy
/*
* 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.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
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.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.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.TypedStringValue;
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.
*
* 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.
*
*
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.
*
*
Note that this class does not 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
* @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();
/** Adapted ConstructorResolver for this factory */
private final ConstructorResolver constructorResolver = new ConstructorResolverAdapter();
/** 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 null
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.
*
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.
*
Default is "true". Turn this off to throw an exception when encountering
* a circular reference, disallowing them completely.
*
NOTE: 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).
*
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.
*
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.
*
NOTE: 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.
*
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.
*
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, 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.setSingleton(false);
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.setSingleton(false);
if (bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
return autowireConstructor(beanClass.getName(), bd).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_BY_NAME && autowireMode != AUTOWIRE_BY_TYPE) {
throw new IllegalArgumentException("Just constants AUTOWIRE_BY_NAME and AUTOWIRE_BY_TYPE allowed");
}
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(existingBean.getClass(), autowireMode, dependencyCheck);
bd.setSingleton(false);
populateBean(existingBean.getClass().getName(), bd, new BeanWrapperImpl(existingBean));
}
public void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException {
RootBeanDefinition bd = getMergedBeanDefinition(beanName, true);
BeanWrapper bw = new BeanWrapperImpl(existingBean);
initBeanWrapper(bw);
applyPropertyValues(beanName, bd, bw, bd.getPropertyValues());
}
public Object configureBean(Object existingBean, String beanName) throws BeansException {
RootBeanDefinition bd = getMergedBeanDefinition(beanName, true);
BeanWrapper bw = new BeanWrapperImpl(existingBean);
initBeanWrapper(bw);
populateBean(beanName, bd, bw);
return initializeBean(beanName, existingBean, bd);
}
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;
}
//---------------------------------------------------------------------
// Implementation of relevant AbstractBeanFactory template methods
//---------------------------------------------------------------------
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
*
Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException {
// Guarantee initialization of beans that the current one depends on.
if (mbd.getDependsOn() != null) {
for (int i = 0; i < mbd.getDependsOn().length; i++) {
getBean(mbd.getDependsOn()[i]);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "' with merged definition [" + mbd + "]");
}
// Make sure bean class is actually resolved at this point.
Class beanClass = resolveBeanClass(mbd, beanName);
// Prepare method overrides.
try {
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
String errorMessage = null;
try {
// Instantiate the bean.
errorMessage = "BeanPostProcessor before instantiation of bean failed";
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
if (beanClass != null &&
!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Object bean = applyBeanPostProcessorsBeforeInstantiation(beanClass, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
return bean;
}
}
// Instantiate the bean.
errorMessage = "Instantiation of bean failed";
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);
// 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.
errorMessage = "Initialization of bean failed";
// 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(bean, beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (continueWithPropertyPopulation) {
populateBean(beanName, mbd, instanceWrapper);
}
Object originalBean = bean;
bean = initializeBean(beanName, bean, mbd);
if (!this.allowRawInjectionDespiteWrapping && originalBean != bean &&
mbd.isSingleton() && hasDependentBean(beanName)) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans " +
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, and also as dependent on specified "dependsOn" beans.
registerDisposableBeanIfNecessary(beanName, originalBean, mbd);
return bean;
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, errorMessage, ex);
}
}
/**
* 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 null
if not predictable
*/
protected Class predictBeanType(String beanName, RootBeanDefinition mbd) {
Class beanClass = null;
if (mbd.getFactoryMethodName() != null) {
beanClass = getTypeForFactoryMethod(beanName, mbd);
}
else {
beanClass = resolveBeanClass(mbd, beanName);
}
// 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.
*
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
* @return the type for the bean if determinable, or null
else
* @see #createBean
*/
protected Class getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd) {
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);
}
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 getObjectType
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).
*
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.
try {
Class type = fb.getObjectType();
if (type != null) {
return type;
}
}
catch (Throwable ex) {
// Thrown from the FactoryBean's getObjectType implementation.
logger.warn("FactoryBean threw exception from getObjectType, despite the contract saying " +
"that it should return null if the type of its object cannot be determined yet", ex);
}
}
// 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
* getObjectType()
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 null
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.
Class beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Object bean = applyBeanPostProcessorsBeforeInstantiation(beanClass, beanName);
if (bean != null) {
instance = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
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
* getObjectType()
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 null
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.
Class beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Object bean = applyBeanPostProcessorsBeforeInstantiation(beanClass, beanName);
if (bean != null) {
instance = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
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 InstantiationAwareBeanPostProcessors to the specified bean definition
* (by class and name), invoking their postProcessBeforeInstantiation
methods.
*
Any returned object will be used as the bean instead of actually instantiating
* the target bean. A null
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 null
* @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) {
BeanWrapper instanceWrapper = null;
if (mbd.getFactoryMethodName() != null) {
instanceWrapper = instantiateUsingFactoryMethod(beanName, mbd, args);
}
else if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() ) {
instanceWrapper = autowireConstructor(beanName, mbd);
}
else {
// No special handling: simply use no-arg constructor.
instanceWrapper = instantiateBean(beanName, mbd);
}
return instanceWrapper;
}
/**
* 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) {
Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
/**
* 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.
*
Implementation requires iterating over the static or instance methods with the
* name specified in the RootBeanDefinition (the method may be overloaded) and trying
* to match with the parameters. We don't have the types attached to constructor args,
* so trial and error is the only way to go here. The explicitArgs array may contain
* argument values passed in programmatically via the corresponding getBean method.
* @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 null
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.
*
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
* @return BeanWrapper for the new instance
*/
protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd) {
return this.constructorResolver.autowireConstructor(beanName, mbd);
}
/**
* 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, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(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, RootBeanDefinition 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);
if (mbd.isSingleton()) {
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.
*
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, RootBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (int i = 0; i < propertyNames.length; i++) {
String propertyName = propertyNames[i];
// look for a matching type
Class requiredType = bw.getPropertyDescriptor(propertyName).getPropertyType();
Map matchingBeans = findAutowireCandidates(beanName, requiredType);
// Let's see how many matching beans we got...
int count = matchingBeans.size();
if (count == 1) {
Map.Entry entry = (Map.Entry) matchingBeans.entrySet().iterator().next();
String autowiredBeanName = (String) entry.getKey();
Object autowiredBean = entry.getValue();
pvs.addPropertyValue(propertyName, autowiredBean);
if (mbd.isSingleton()) {
registerDependentBean(autowiredBeanName, beanName);
}
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
else if (count > 1) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, propertyName,
"There are " + matchingBeans.size() + " beans of type [" + requiredType.getName() +
"] available for autowiring by type: " + matchingBeans.keySet() +
". There should have been exactly 1 to be able to autowire property '" +
propertyName + "' of bean '" + beanName + "'. Consider using autowiring by name instead.");
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by type: no matching bean found");
}
}
}
}
/**
* 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(RootBeanDefinition 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.
*
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, RootBeanDefinition 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, RootBeanDefinition 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());
}
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this, beanName, mbd, bw);
// Create a deep copy, resolving any references for values.
BeanWrapperImpl bwi = (bw instanceof BeanWrapperImpl ? (BeanWrapperImpl) bw : null);
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("bean property '" + propertyName + "'", originalValue);
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (bwi != null && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName)) {
pv.setConvertedValue(bwi.convertForProperty(resolvedValue, propertyName));
}
deepCopy.add(pv);
}
else if (originalValue instanceof TypedStringValue &&
bwi != null && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName)) {
pv.setConvertedValue(bwi.convertForProperty(resolvedValue, propertyName));
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(propertyName, 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);
}
}
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
*
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 null
, 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 null
, 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 {
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
if (mbd != null && mbd.getInitMethodName() != null) {
invokeCustomInitMethod(
beanName, bean, mbd.getInitMethodName(), mbd.isEnforceInitMethod());
}
}
/**
* Invoke the specified custom init method on the given bean.
* Called by invokeInitMethods.
*
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;
}
}
if (!Modifier.isPublic(initMethod.getModifiers()) ||
!Modifier.isPublic(initMethod.getDeclaringClass().getModifiers())) {
initMethod.setAccessible(true);
}
try {
initMethod.invoke(bean, (Object[]) null);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
/**
* Applies the postProcessAfterInitialization
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.
*
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 type of the autowired property or argument
* @return a Map of candidate names and candidate instances that match
* the required type (never null
)
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map findAutowireCandidates(String beanName, Class requiredType) throws BeansException {
Map result = findMatchingBeans(requiredType);
return (result != null ? result : Collections.EMPTY_MAP);
}
/**
* Find bean instances that match the required type. Called by autowiring.
* @param requiredType the type of the beans to look up
* @return a Map of bean names and bean instances that match the required type,
* or null
if none found
* @throws BeansException in case of errors
* @deprecated as of Spring 2.0.1: Override findAutowireCandidates
instead
*/
protected Map findMatchingBeans(Class requiredType) throws BeansException {
throw new FatalBeanException("Bean lookup by type not supported by this factory");
}
//---------------------------------------------------------------------
// 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());
}
protected Map findAutowireCandidates(String beanName, Class requiredType) throws BeansException {
return AbstractAutowireCapableBeanFactory.this.findAutowireCandidates(beanName, requiredType);
}
}
}