📄 abstractautowirecapablebeanfactory.java
字号:
throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Resolving reference from property '" + argName + "' in bean '" +
beanName + "' to bean '" + ref.getBeanName() + "'");
}
try {
if (ref.isToParent()) {
if (getParentBeanFactory() == null) {
throw new BeanCreationException(
mergedBeanDefinition.getResourceDescription(), beanName,
"Can't resolve reference to bean '" + ref.getBeanName() +
"' in parent factory: no parent factory available");
}
return getParentBeanFactory().getBean(ref.getBeanName());
}
else {
if (mergedBeanDefinition.isSingleton()) {
registerDependentBean(ref.getBeanName(), beanName);
}
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, List ml)
throws BeansException {
List resolved = new ArrayList(ml.size());
for (int i = 0; i < ml.size(); i++) {
resolved.add(
resolveValueIfNecessary(
beanName, mergedBeanDefinition,
argName + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
ml.get(i)));
}
return resolved;
}
/**
* For each element in the ManagedList, resolve reference if necessary.
*/
protected Set resolveManagedSet(
String beanName, RootBeanDefinition mergedBeanDefinition, String argName, Set ms)
throws BeansException {
Set resolved = new HashSet(ms.size());
int i = 0;
for (Iterator it = ms.iterator(); it.hasNext();) {
resolved.add(
resolveValueIfNecessary(
beanName, mergedBeanDefinition,
argName + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
it.next()));
i++;
}
return resolved;
}
/**
* For each element in the ManagedMap, resolve reference if necessary.
*/
protected Map resolveManagedMap(
String beanName, RootBeanDefinition mergedBeanDefinition, String argName, Map mm)
throws BeansException {
Map resolved = CollectionFactory.createLinkedMapIfPossible(mm.size());
Iterator keys = mm.keySet().iterator();
while (keys.hasNext()) {
Object key = keys.next();
resolved.put(
key,
resolveValueIfNecessary(
beanName, mergedBeanDefinition,
argName + BeanWrapper.PROPERTY_KEY_PREFIX + key + BeanWrapper.PROPERTY_KEY_SUFFIX,
mm.get(key)));
}
return resolved;
}
/**
* Register a dependent bean for the given bean,
* to be destroyed before the given bean is destroyed.
* @param beanName the name of the bean
* @param dependentBeanName the name of the dependent bean
*/
protected final void registerDependentBean(String beanName, String dependentBeanName) {
synchronized (this.dependentBeanMap) {
List dependencies = (List) this.dependentBeanMap.get(beanName);
if (dependencies == null) {
dependencies = new LinkedList();
this.dependentBeanMap.put(beanName, dependencies);
}
dependencies.add(dependentBeanName);
}
}
/**
* 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.
* @throws Throwable if thrown by init methods or by the invocation process
*/
protected void invokeInitMethods(String beanName, RootBeanDefinition mergedBeanDefinition, Object bean)
throws Throwable {
if (bean instanceof InitializingBean) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with beanName '" + beanName + "'");
}
((InitializingBean) bean).afterPropertiesSet();
}
if (mergedBeanDefinition.getInitMethodName() != null) {
invokeCustomInitMethod(beanName, bean, mergedBeanDefinition.getInitMethodName(),
mergedBeanDefinition.getResourceDescription());
}
}
/**
* Invoke the specified custom init method on the given bean.
* <p>Can be overridden in subclasses for custom resolution of init
* methods with arguments.
*/
protected void invokeCustomInitMethod(String beanName, Object bean, String initMethodName,
String resourceDescription) throws Throwable {
if (logger.isDebugEnabled()) {
logger.debug("Invoking custom init method '" + initMethodName +
"' on bean with beanName '" + beanName + "'");
}
try {
Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null);
if (initMethod == null) {
throw new NoSuchMethodException("Couldn't find an init method named '" + initMethodName +
"' on bean with name '" + beanName + "'");
}
if (!Modifier.isPublic(initMethod.getModifiers())) {
initMethod.setAccessible(true);
}
initMethod.invoke(bean, null);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
public void destroySingletons() {
super.destroySingletons();
if (logger.isInfoEnabled()) {
logger.info("Destroying inner beans in factory {" + this + "}");
}
synchronized (this.disposableInnerBeans) {
for (Iterator it = new HashSet(this.disposableInnerBeans.keySet()).iterator(); it.hasNext();) {
destroyDisposableInnerBean((String) it.next());
}
}
}
protected void destroyBean(String beanName, Object bean) {
if (logger.isDebugEnabled()) {
logger.debug("Retrieving dependent beans for bean '" + beanName + "'");
}
List dependencies = (List) this.dependentBeanMap.remove(beanName);
if (dependencies != null) {
for (Iterator it = dependencies.iterator(); it.hasNext();) {
String dependentBeanName = (String) it.next();
if (containsBean(dependentBeanName)) {
// registered singleton
destroySingleton(dependentBeanName);
}
else {
// disposable inner bean
destroyDisposableInnerBean(dependentBeanName);
}
}
}
if (logger.isDebugEnabled()) {
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) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking destroy() on bean with name '" + beanName + "'");
}
try {
((DisposableBean) bean).destroy();
}
catch (Throwable ex) {
logger.error("destroy() on bean with name '" + beanName + "' threw an exception", ex);
}
}
try {
RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
if (bd.getDestroyMethodName() != null) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking custom destroy method '" + bd.getDestroyMethodName() +
"' on bean with name '" + beanName + "'");
}
invokeCustomDestroyMethod(beanName, bean, bd.getDestroyMethodName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// ignore, from manually registered singleton
}
}
/**
* Destroy the given inner bean. Delegates to destroyBean if a corresponding
* disposable inner bean instance is found.
* @param innerBeanName name of the inner bean
* @see #destroyBean
*/
private void destroyDisposableInnerBean(String innerBeanName) {
Object innerBeanInstance = this.disposableInnerBeans.remove(innerBeanName);
if (innerBeanInstance != null) {
destroyBean(innerBeanName, innerBeanInstance);
}
}
/**
* 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 destroyMethod =
BeanUtils.findDeclaredMethodWithMinimalParameters(bean.getClass(), destroyMethodName);
if (destroyMethod == null) {
logger.error("Couldn't find a destroy method named '" + destroyMethodName +
"' on bean with name '" + beanName + "'");
}
else {
Class[] paramTypes = destroyMethod.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;
}
if (!Modifier.isPublic(destroyMethod.getModifiers())) {
destroyMethod.setAccessible(true);
}
try {
destroyMethod.invoke(bean, args);
}
catch (InvocationTargetException ex) {
logger.error("Couldn't invoke destroy method '" + destroyMethodName +
"' of bean with name '" + beanName + "'", ex.getTargetException());
}
catch (Throwable ex) {
logger.error("Couldn't invoke destroy method '" + destroyMethodName +
"' of bean with name '" + beanName + "'", ex);
}
}
}
}
//---------------------------------------------------------------------
// Abstract method 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -