📄 abstractautowirecapablebeanfactory.java
字号:
throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName,
"Error setting property values", ex);
}
}
/**
* Given a PropertyValue, return a value, resolving any references to other
* beans in the factory if necessary. The value could be:
* <li>A BeanDefinition, which leads to the creation of a corresponding
* new bean instance. Singleton flags and names of such "inner beans"
* are always ignored: Inner beans are anonymous prototypes.
* <li>A RuntimeBeanReference, which must be resolved.
* <li>A ManagedList. This is a special collection that may contain
* RuntimeBeanReferences or Collections that will need to be resolved.
* <li>A ManagedSet. May also contain RuntimeBeanReferences or
* Collections that will need to be resolved.
* <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
* or Collection that will need to be resolved.
* <li>An ordinary object or null, in which case it's left alone.
*/
protected Object resolveValueIfNecessary(String beanName, RootBeanDefinition mergedBeanDefinition,
String argName, Object value) throws BeansException {
// We must check each PropertyValue to see whether it
// requires a runtime reference to another bean to be resolved.
// If it does, we'll attempt to instantiate the bean and set the reference.
if (value instanceof AbstractBeanDefinition) {
BeanDefinition bd = (BeanDefinition) value;
if (bd instanceof AbstractBeanDefinition) {
// an inner bean should never be cached as singleton
((AbstractBeanDefinition) bd).setSingleton(false);
}
String innerBeanName = "(inner bean for property '" + beanName + "." + argName + "')";
Object bean = createBean(innerBeanName, getMergedBeanDefinition(innerBeanName, bd));
if (bean instanceof DisposableBean) {
// keep reference to inner bean, to be able to destroy it on factory shutdown
this.disposableInnerBeans.add(bean);
}
return getObjectForSharedInstance(innerBeanName, bean);
}
else if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(beanName, mergedBeanDefinition, argName, ref);
}
else if (value instanceof ManagedList) {
// Convert from managed list. This is a special container that may
// contain runtime bean references. May need to resolve references.
return resolveManagedList(beanName, mergedBeanDefinition, argName, (ManagedList) value);
}
else if (value instanceof ManagedSet) {
// Convert from managed set. This is a special container that may
// contain runtime bean references. May need to resolve references.
return resolveManagedSet(beanName, mergedBeanDefinition, argName, (ManagedSet) value);
}
else if (value instanceof ManagedMap) {
// Convert from managed map. This is a special container that may
// contain runtime bean references. May need to resolve references.
ManagedMap mm = (ManagedMap) value;
return resolveManagedMap(beanName, mergedBeanDefinition, argName, mm);
}
else {
// no need to resolve value
return value;
}
}
/**
* Resolve a reference to another bean in the factory.
*/
protected Object resolveReference(String beanName, RootBeanDefinition mergedBeanDefinition,
String argName, RuntimeBeanReference ref) throws BeansException {
try {
logger.debug("Resolving reference from property '" + argName + "' in bean '" +
beanName + "' to bean '" + ref.getBeanName() + "'");
return getBean(ref.getBeanName());
}
catch (BeansException ex) {
throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName,
"Can't resolve reference to bean '" + ref.getBeanName() +
"' while setting property '" + argName + "'", ex);
}
}
/**
* For each element in the ManagedList, resolve reference if necessary.
*/
protected List resolveManagedList(String beanName, RootBeanDefinition mergedBeanDefinition,
String argName, ManagedList ml) throws BeansException {
List resolved = new ArrayList();
for (int i = 0; i < ml.size(); i++) {
resolved.add(resolveValueIfNecessary(beanName, mergedBeanDefinition, argName + "[" + i + "]", ml.get(i)));
}
return resolved;
}
/**
* For each element in the ManagedList, resolve reference if necessary.
*/
protected Set resolveManagedSet(String beanName, RootBeanDefinition mergedBeanDefinition,
String argName, ManagedSet ms) throws BeansException {
Set resolved = new HashSet();
for (Iterator it = ms.iterator(); it.hasNext();) {
resolved.add(resolveValueIfNecessary(beanName, mergedBeanDefinition, argName + "[(set-element)]", it.next()));
}
return resolved;
}
/**
* For each element in the ManagedMap, resolve reference if necessary.
*/
protected Map resolveManagedMap(String beanName, RootBeanDefinition mergedBeanDefinition,
String argName, ManagedMap mm) throws BeansException {
Map resolved = new HashMap();
Iterator keys = mm.keySet().iterator();
while (keys.hasNext()) {
Object key = keys.next();
resolved.put(key, resolveValueIfNecessary(beanName, mergedBeanDefinition, argName + "[" + key + "]", mm.get(key)));
}
return resolved;
}
/**
* 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
* and/or BeanFactoryAware, and invoking the necessary callback(s) if it does.
* @param bean new bean instance we may need to initialize
* @param beanName the bean has in the factory. Used for debug output.
*/
protected void invokeInitMethods(String beanName, RootBeanDefinition mergedBeanDefinition, Object bean)
throws Exception {
if (bean instanceof InitializingBean) {
logger.debug("Calling afterPropertiesSet() on bean with beanName '" + beanName + "'");
((InitializingBean) bean).afterPropertiesSet();
}
if (mergedBeanDefinition.getInitMethodName() != null) {
logger.debug("Calling custom init method '" + mergedBeanDefinition.getInitMethodName() +
"' on bean with beanName '" + beanName + "'");
try {
bean.getClass().getMethod(mergedBeanDefinition.getInitMethodName(), null).invoke(bean, null);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName,
"Initialization method '" + mergedBeanDefinition.getInitMethodName() +
"' threw exception", ex.getTargetException());
}
catch (Exception ex) {
throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName,
"Invocation of initialization method '" +
mergedBeanDefinition.getInitMethodName() + "' failed", ex);
}
}
}
public void destroySingletons() {
super.destroySingletons();
synchronized (this.disposableInnerBeans) {
for (Iterator it = this.disposableInnerBeans.iterator(); it.hasNext();) {
Object bean = it.next();
it.remove();
destroyBean("(inner bean of type " + bean.getClass().getName() + ")", bean);
}
}
}
protected void destroyBean(String beanName, Object bean) {
logger.debug("Retrieving depending beans for bean '" + beanName + "'");
String[] dependingBeans = getDependingBeanNames(beanName);
if (dependingBeans != null) {
for (int i = 0; i < dependingBeans.length; i++) {
destroySingleton(dependingBeans[i]);
}
}
logger.debug("Applying DestructionAwareBeanPostProcessors to bean with name '" + beanName + "'");
for (int i = getBeanPostProcessors().size() - 1; i >= 0; i--) {
Object beanProcessor = getBeanPostProcessors().get(i);
if (beanProcessor instanceof DestructionAwareBeanPostProcessor) {
((DestructionAwareBeanPostProcessor) beanProcessor).postProcessBeforeDestruction(bean, beanName);
}
}
if (bean instanceof DisposableBean) {
logger.debug("Calling destroy() on bean with name '" + beanName + "'");
try {
((DisposableBean) bean).destroy();
}
catch (Exception ex) {
logger.error("destroy() on bean with name '" + beanName + "' threw an exception", ex);
}
}
try {
RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
if (bd.getDestroyMethodName() != null) {
logger.debug("Calling custom destroy method '" + bd.getDestroyMethodName() +
"' on bean with name '" + beanName + "'");
invokeCustomDestroyMethod(beanName, bean, bd.getDestroyMethodName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// ignore, from manually registered singleton
}
}
/**
* Invoke the specified custom destroy method on the given bean.
* <p>This implementation invokes a no-arg method if found, else checking
* for a method with a single boolean argument (passing in "true",
* assuming a "force" parameter), else logging an error.
* <p>Can be overridden in subclasses for custom resolution of destroy
* methods with arguments.
*/
protected void invokeCustomDestroyMethod(String beanName, Object bean, String destroyMethodName) {
Method[] methods = bean.getClass().getMethods();
Method targetMethod = null;
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(destroyMethodName)) {
if (targetMethod == null ||
methods[i].getParameterTypes().length < targetMethod.getParameterTypes().length) {
targetMethod = methods[i];
}
}
}
if (targetMethod == null) {
logger.error("Couldn't find a method named '" + destroyMethodName +
"' on bean with name '" + beanName + "'");
}
else {
Class[] paramTypes = targetMethod.getParameterTypes();
if (paramTypes.length > 1) {
logger.error("Method '" + destroyMethodName + "' of bean '" + beanName +
"' has more than one parameter - not supported as destroy method");
}
else if (paramTypes.length == 1 && !paramTypes[0].equals(boolean.class)) {
logger.error("Method '" + destroyMethodName + "' of bean '" + beanName +
"' has a non-boolean parameter - not supported as destroy method");
}
else {
Object[] args = new Object[paramTypes.length];
if (paramTypes.length == 1) {
args[0] = Boolean.TRUE;
}
try {
targetMethod.invoke(bean, args);
}
catch (InvocationTargetException ex) {
logger.error("Couldn't invoke destroy method '" + destroyMethodName +
"' of bean with name '" + beanName + "'", ex.getTargetException());
}
catch (Exception ex) {
logger.error("Couldn't invoke destroy method '" + destroyMethodName +
"' of bean with name '" + beanName + "'", ex);
}
}
}
}
//---------------------------------------------------------------------
// Abstract methods to be implemented by concrete subclasses
//---------------------------------------------------------------------
/**
* Find bean instances that match the required type. Called by autowiring.
* If a subclass cannot obtain information about bean names by type,
* a corresponding exception should be thrown.
* @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
* @see #autowireByType
* @see #autowireConstructor
*/
protected abstract Map findMatchingBeans(Class requiredType) throws BeansException;
/**
* Return the names of the beans that depend on the given bean.
* Called by destroyBean, to be able to destroy depending beans first.
* @param beanName name of the bean to find depending beans for
* @return array of names of depending beans, or null if none
* @throws BeansException in case of errors
* @see #destroyBean
*/
protected abstract String[] getDependingBeanNames(String beanName) throws BeansException;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -