abstractbeanfactory.java
来自「spring framework 2.5.4源代码」· Java 代码 · 共 1,409 行 · 第 1/4 页
JAVA
1,409 行
* Check the given merged bean definition,
* potentially throwing validation exceptions.
* @param mbd the merged bean definition to check
* @param beanName the name of the bean
* @param args the arguments for bean creation, if any
* @throws BeanDefinitionStoreException in case of validation failure
*/
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, Object[] args)
throws BeanDefinitionStoreException {
// check if bean definition is not abstract
if (mbd.isAbstract()) {
throw new BeanIsAbstractException(beanName);
}
// Check validity of the usage of the args parameter. This can
// only be used for prototypes constructed via a factory method.
if (args != null && !mbd.isPrototype()) {
throw new BeanDefinitionStoreException(
"Can only specify arguments for the getBean method when referring to a prototype bean definition");
}
}
/**
* Remove the merged bean definition for the specified bean,
* recreating it on next access.
* @param beanName the bean name to clear the merged definition for
*/
protected void clearMergedBeanDefinition(String beanName) {
this.mergedBeanDefinitions.remove(beanName);
}
/**
* Resolve the bean class for the specified bean definition,
* resolving a bean class name into a Class reference (if necessary)
* and storing the resolved Class in the bean definition for further use.
* @param mbd the merged bean definition to determine the class for
* @param beanName the name of the bean (for error handling purposes)
* @return the resolved bean class (or <code>null</code> if none)
* @throws CannotLoadBeanClassException if we failed to load the class
*/
protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName) {
return resolveBeanClass(mbd, beanName, null);
}
/**
* Resolve the bean class for the specified bean definition,
* resolving a bean class name into a Class reference (if necessary)
* and storing the resolved Class in the bean definition for further use.
* @param mbd the merged bean definition to determine the class for
* @param beanName the name of the bean (for error handling purposes)
* @param typesToMatch the types to match in case of internal type matching purposes
* (also signals that the returned <code>Class</code> will never be exposed to application code)
* @return the resolved bean class (or <code>null</code> if none)
* @throws CannotLoadBeanClassException if we failed to load the class
*/
protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName, Class[] typesToMatch)
throws CannotLoadBeanClassException {
try {
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
if (typesToMatch != null) {
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (int i = 0; i < typesToMatch.length; i++) {
dcl.excludeClass(typesToMatch[i].getName());
}
}
String className = mbd.getBeanClassName();
return (className != null ? ClassUtils.forName(className, tempClassLoader) : null);
}
}
return mbd.resolveBeanClass(getBeanClassLoader());
}
catch (ClassNotFoundException ex) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (LinkageError err) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
}
}
/**
* Predict the eventual bean type (of the processed bean instance) for the
* specified bean. Called by {@link #getType} and {@link #isTypeMatch}.
* Does not need to handle FactoryBeans specifically, since it is only
* supposed to operate on the raw bean type.
* <p>This implementation is simplistic in that it is not able to
* handle factory methods and InstantiationAwareBeanPostProcessors.
* It only predicts the bean type correctly for a standard bean.
* To be overridden in subclasses, applying more sophisticated type detection.
* @param beanName the name of the bean
* @param mbd the merged bean definition to determine the type for
* @param typesToMatch the types to match in case of internal type matching purposes
* (also signals that the returned <code>Class</code> will never be exposed to application code)
* @return the type of the bean, or <code>null</code> if not predictable
*/
protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) {
if (mbd.getFactoryMethodName() != null) {
return null;
}
return resolveBeanClass(mbd, beanName, typesToMatch);
}
/**
* Check whether the given bean is defined as a {@link FactoryBean}.
* @param beanName the name of the bean
* @param mbd the corresponding bean definition
*/
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Class beanClass = predictBeanType(beanName, mbd, new Class[] {FactoryBean.class});
return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
}
/**
* Determine the bean type for the given FactoryBean definition, as far as possible.
* Only called if there is no singleton instance registered for the target bean already.
* <p>The default implementation creates the FactoryBean via <code>getBean</code>
* to call its <code>getObjectType</code> method. Subclasses are encouraged to optimize
* this, typically by just instantiating the FactoryBean but not populating it yet,
* trying whether its <code>getObjectType</code> method already returns a type.
* If no type found, a full FactoryBean creation as performed by this implementation
* should be used as fallback.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @return the type for the bean if determinable, or <code>null</code> else
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
* @see #getBean(String)
*/
protected Class getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
if (!mbd.isSingleton()) {
return null;
}
try {
FactoryBean factoryBean =
(FactoryBean) doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
return getTypeForFactoryBean(factoryBean);
}
catch (BeanCreationException ex) {
// Can only happen when getting a FactoryBean.
if (logger.isDebugEnabled()) {
logger.debug("Ignoring bean creation exception on FactoryBean type check: " + ex);
}
onSuppressedException(ex);
return null;
}
}
/**
* Mark the specified bean as already created (or about to be created).
* <p>This allows the bean factory to optimize its caching for repeated
* creation of the specified bean.
* @param beanName the name of the bean
*/
protected void markBeanAsCreated(String beanName) {
this.alreadyCreated.add(beanName);
}
/**
* Determine whether the specified bean is eligible for having
* its bean definition metadata cached.
* @param beanName the name of the bean
* @return <code>true</code> if the bean's metadata may be cached
* at this point already
*/
protected boolean isBeanEligibleForMetadataCaching(String beanName) {
return this.alreadyCreated.contains(beanName);
}
/**
* Remove the singleton instance (if any) for the given bean name,
* but only if it hasn't been used for other purposes than type checking.
* @param beanName the name of the bean
* @return <code>true</code> if actually removed, <code>false</code> otherwise
*/
protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
removeSingleton(beanName);
return true;
}
else {
return false;
}
}
/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
* @param beanInstance the shared bean instance
* @param name name that may include factory dereference prefix
* @param beanName the canonical bean name
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean factory = (FactoryBean) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
/**
* Determine whether the given bean name is already in use within this factory,
* i.e. whether there is a local bean or alias registered under this name or
* an inner bean created with this name.
* @param beanName the name to check
*/
public boolean isBeanNameInUse(String beanName) {
return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
}
/**
* Determine whether the given bean requires destruction on shutdown.
* <p>The default implementation checks the DisposableBean interface as well as
* a specified destroy method and registered DestructionAwareBeanPostProcessors.
* @param bean the bean instance to check
* @param mbd the corresponding bean definition
* @see org.springframework.beans.factory.DisposableBean
* @see AbstractBeanDefinition#getDestroyMethodName()
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
*/
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
return (bean instanceof DisposableBean || mbd.getDestroyMethodName() != null ||
hasDestructionAwareBeanPostProcessors());
}
/**
* Add the given bean to the list of disposable beans in this factory,
* registering its DisposableBean interface and/or the given destroy method
* to be called on factory shutdown (if applicable). Only applies to singletons.
* @param beanName the name of the bean
* @param bean the bean instance
* @param mbd the bean definition for the bean
* @see RootBeanDefinition#isSingleton
* @see RootBeanDefinition#getDependsOn
* @see #registerDisposableBean
* @see #registerDependentBean
*/
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
}
else {
// A bean with a custom scope...
Scope scope = (Scope) this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
}
}
}
//---------------------------------------------------------------------
// Abstract methods to be implemented by subclasses
//---------------------------------------------------------------------
/**
* Check if this bean factory contains a bean definition with the given name.
* Does not consider any hierarchy this factory may participate in.
* Invoked by <code>containsBean</code> when no cached singleton instance is found.
* <p>Depending on the nature of the concrete bean factory implementation,
* this operation might be expensive (for example, because of directory lookups
* in external registries). However, for listable bean factories, this usually
* just amounts to a local hash lookup: The operation is therefore part of the
* public interface there. The same implementation can serve for both this
* template method and the public interface method in that case.
* @param beanName the name of the bean to look for
* @return if this bean factory contains a bean definition with the given name
* @see #containsBean
* @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition
*/
protected abstract boolean containsBeanDefinition(String beanName);
/**
* Return the bean definition for the given bean name.
* Subclasses should normally implement caching, as this method is invoked
* by this class every time bean definition metadata is needed.
* <p>Depending on the nature of the concrete bean factory implementation,
* this operation might be expensive (for example, because of directory lookups
* in external registries). However, for listable bean factories, this usually
* just amounts to a local hash lookup: The operation is therefore part of the
* public interface there. The same implementation can serve for both this
* template method and the public interface method in that case.
* @param beanName the name of the bean to find a definition for
* @return the BeanDefinition for this prototype name (never <code>null</code>)
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
* if the bean definition cannot be resolved
* @throws BeansException in case of errors
* @see RootBeanDefinition
* @see ChildBeanDefinition
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
*/
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
/**
* Create a bean instance for the given bean definition.
* The bean definition will already have been merged with the parent
* definition in case of a child definition.
* <p>All the other methods in this class invoke this method, although
* beans may be cached after being instantiated by this method. All bean
* instantiation within this class is performed by this method.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args arguments to use if creating a prototype using explicit arguments to a
* static factory method. This parameter must be <code>null</code> except in this case.
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
*/
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?