📄 abstractbeanfactory.java
字号:
* @param beanName the name of the prototype that has been created
* @see #isPrototypeCurrentlyInCreation
*/
protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.set(null);
}
else if (curVal instanceof Set) {
Set beanNameSet = (Set) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.set(null);
}
}
}
/**
* Return whether the specified prototype bean is currently in creation
* (within the current thread).
* @param beanName the name of the bean
*/
protected final boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set) curVal).contains(beanName))));
}
public boolean isCurrentlyInCreation(String beanName) {
return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName);
}
public void destroyBean(String beanName, Object beanInstance) {
destroyBean(beanName, beanInstance, getMergedBeanDefinition(beanName));
}
/**
* Destroy the given bean instance (usually a prototype instance
* obtained from this factory) according to the given bean definition.
* @param beanName the name of the bean definition
* @param beanInstance the bean instance to destroy
* @param mbd the merged bean definition
*/
protected void destroyBean(String beanName, Object beanInstance, RootBeanDefinition mbd) {
new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors()).destroy();
}
public void destroyScopedBean(String beanName) {
RootBeanDefinition mbd = getMergedBeanDefinition(beanName);
if (mbd.isSingleton() || mbd.isPrototype()) {
throw new IllegalArgumentException(
"Bean name '" + beanName + "' does not correspond to an object in a Scope");
}
String scopeName = mbd.getScope();
Scope scope = (Scope) this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
Object bean = scope.remove(beanName);
if (bean != null) {
destroyBean(beanName, bean, mbd);
}
}
//---------------------------------------------------------------------
// Implementation methods
//---------------------------------------------------------------------
/**
* Return the bean name, stripping out the factory dereference prefix if necessary,
* and resolving aliases to canonical names.
* @param name the user-specified name
* @return the transformed bean name
*/
protected String transformedBeanName(String name) {
String canonicalName = BeanFactoryUtils.transformedBeanName(name);
// Handle aliasing.
String resolvedName = null;
do {
resolvedName = (String) this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
/**
* Determine the original bean name, resolving locally defined aliases to canonical names.
* @param name the user-specified name
* @return the original bean name
*/
protected String originalBeanName(String name) {
String beanName = transformedBeanName(name);
if (name.startsWith(FACTORY_BEAN_PREFIX)) {
beanName = FACTORY_BEAN_PREFIX + beanName;
}
return beanName;
}
/**
* Determine whether this given bean name is defines as an alias
* (as opposed to the name of an actual bean definition).
* @param beanName the bean name to check
* @return whether the given name is an alias
*/
protected boolean isAlias(String beanName) {
return this.aliasMap.containsKey(beanName);
}
/**
* Initialize the given BeanWrapper with the custom editors registered
* with this factory. To be called for BeanWrappers that will create
* and populate bean instances.
* <p>The default implementation delegates to <code>registerCustomEditors</code>.
* Can be overridden in subclasses.
* @param bw the BeanWrapper to initialize
* @see #registerCustomEditors
*/
protected void initBeanWrapper(BeanWrapper bw) {
registerCustomEditors(bw);
}
/**
* Initialize the given PropertyEditorRegistry with the custom editors
* registered with this BeanFactory.
* <p>To be called for BeanWrappers that will create and populate bean
* instances, and for SimpleTypeConverter used for constructor argument
* and factory method type conversion.
* @param registry the PropertyEditorRegistry to initialize
*/
protected void registerCustomEditors(PropertyEditorRegistry registry) {
PropertyEditorRegistrySupport registrySupport =
(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
if (registrySupport != null) {
registrySupport.useConfigValueEditors();
}
for (Iterator it = this.propertyEditorRegistrars.iterator(); it.hasNext();) {
PropertyEditorRegistrar registrar = (PropertyEditorRegistrar) it.next();
registrar.registerCustomEditors(registry);
}
for (Iterator it = this.customEditors.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Class clazz = (Class) entry.getKey();
PropertyEditor editor = (PropertyEditor) entry.getValue();
// Register the editor as shared instance, if possible,
// to make it clear that it might be used concurrently.
if (registrySupport != null) {
registrySupport.registerSharedEditor(clazz, editor);
}
else {
registry.registerCustomEditor(clazz, editor);
}
}
}
/**
* Return a RootBeanDefinition for the given bean name,
* merging a child bean definition with its parent if necessary.
* @param beanName the name of the bean to retrieve the merged definition for
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
public RootBeanDefinition getMergedBeanDefinition(String beanName) throws BeansException {
return getMergedBeanDefinition(beanName, false);
}
/**
* Return a RootBeanDefinition, even by traversing parent if the parameter is a
* child definition. Can ask the parent bean factory if not found in this instance.
* @param beanName the name of the bean to retrieve the merged definition for
* @param includingAncestors whether to ask the parent bean factory if not found
* in this instance
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedBeanDefinition(String beanName, boolean includingAncestors)
throws BeansException {
// Efficiently check whether bean definition exists in this factory.
if (includingAncestors && !containsBeanDefinition(beanName) &&
getParentBeanFactory() instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName, true);
}
// Resolve merged bean definition locally.
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
/**
* Return a RootBeanDefinition for the given top-level bean, by merging with
* the parent if the given bean's definition is a child bean definition.
* @param beanName the name of the bean definition
* @param bd the original bean definition (Root/ChildBeanDefinition)
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
/**
* Return a RootBeanDefinition for the given bean, by merging with the
* parent if the given bean's definition is a child bean definition.
* @param beanName the name of the bean definition
* @param bd the original bean definition (Root/ChildBeanDefinition)
* @param containingBd the containing bean definition in case of inner bean,
* or <code>null</code> in case of a top-level bean
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, BeanDefinition containingBd)
throws BeanDefinitionStoreException {
RootBeanDefinition mbd = null;
// Quick check on the concurrent map first, with minimal locking.
if (containingBd == null) {
mbd = (RootBeanDefinition) this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
synchronized (this.mergedBeanDefinitions) {
// Second check with full lock now, to enforce the same merged instance.
if (containingBd == null) {
mbd = (RootBeanDefinition) this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
if (bd instanceof RootBeanDefinition) {
// Use copy of given root bean definition.
mbd = new RootBeanDefinition((RootBeanDefinition) bd);
}
else if (bd instanceof ChildBeanDefinition) {
// Child bean definition: needs to be merged with parent.
ChildBeanDefinition cbd = (ChildBeanDefinition) bd;
RootBeanDefinition pbd = null;
try {
String parentBeanName = transformedBeanName(cbd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName, true);
}
else {
if (getParentBeanFactory() instanceof AbstractBeanFactory) {
AbstractBeanFactory parentFactory = (AbstractBeanFactory) getParentBeanFactory();
pbd = parentFactory.getMergedBeanDefinition(parentBeanName, true);
}
else {
throw new NoSuchBeanDefinitionException(cbd.getParentName(),
"Parent name '" + cbd.getParentName() + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(cbd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + cbd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(cbd);
}
else {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Definition is neither a RootBeanDefinition nor a ChildBeanDefinition: " + bd);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setSingleton(false);
}
// Only cache the merged bean definition if we're already about to create an
// instance of the bean, or at least have already created an instance before.
if (containingBd == null && isCacheBeanMetadata() && this.alreadyCreated.contains(beanName)) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
}
}
return mbd;
}
/**
* 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) {
if (mbd.isSingleton()) {
throw new BeanDefinitionStoreException(
"Cannot specify arguments in the getBean() method when referring to a singleton bean definition");
}
else if (mbd.getFactoryMethodName() == null) {
throw new BeanDefinitionStoreException(
"Can only specify arguments in the getBean() method in conjunction with a factory method");
}
}
}
/**
* 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) throws CannotLoadBeanClassException {
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
try {
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);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -