All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * 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); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy