Preserve resolved destroy method name in RootBeanDefinition
Closes gh-26498
This commit is contained in:
parent
d5e5dcb7e1
commit
809813dd52
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2020 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -119,14 +119,16 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
if (destroyMethod.getParameterCount() > 0) {
|
||||||
if (paramTypes.length > 1) {
|
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
if (paramTypes.length > 1) {
|
||||||
beanName + "' has more than one parameter - not supported as destroy method");
|
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||||
}
|
beanName + "' has more than one parameter - not supported as destroy method");
|
||||||
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
}
|
||||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
||||||
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||||
|
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
|
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
|
||||||
}
|
}
|
||||||
|
@ -170,66 +172,6 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the current value of the given beanDefinition's "destroyMethodName" property is
|
|
||||||
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
|
|
||||||
* Candidate methods are currently limited to public, no-arg methods named "close" or
|
|
||||||
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
|
|
||||||
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
|
|
||||||
* to the name of the inferred method. This constant serves as the default for the
|
|
||||||
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
|
|
||||||
* used in XML within the {@code <bean destroy-method="">} or {@code
|
|
||||||
* <beans default-destroy-method="">} attributes.
|
|
||||||
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
|
||||||
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
|
||||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
|
||||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
|
||||||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
|
||||||
// Only perform destroy method inference or Closeable detection
|
|
||||||
// in case of the bean not explicitly implementing DisposableBean
|
|
||||||
if (!(bean instanceof DisposableBean)) {
|
|
||||||
try {
|
|
||||||
return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
|
||||||
}
|
|
||||||
catch (NoSuchMethodException ex) {
|
|
||||||
try {
|
|
||||||
return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
|
||||||
}
|
|
||||||
catch (NoSuchMethodException ex2) {
|
|
||||||
// no candidate destroy method found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for all DestructionAwareBeanPostProcessors in the List.
|
|
||||||
* @param processors the List to search
|
|
||||||
* @return the filtered List of DestructionAwareBeanPostProcessors
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(
|
|
||||||
List<DestructionAwareBeanPostProcessor> processors, Object bean) {
|
|
||||||
|
|
||||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
|
||||||
if (!CollectionUtils.isEmpty(processors)) {
|
|
||||||
filteredPostProcessors = new ArrayList<>(processors.size());
|
|
||||||
for (DestructionAwareBeanPostProcessor processor : processors) {
|
|
||||||
if (processor.requiresDestruction(bean)) {
|
|
||||||
filteredPostProcessors.add(processor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filteredPostProcessors;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
destroy();
|
destroy();
|
||||||
|
@ -384,12 +326,50 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
|
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
|
||||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
|
}
|
||||||
return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
|
|
||||||
ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
|
|
||||||
|
/**
|
||||||
|
* If the current value of the given beanDefinition's "destroyMethodName" property is
|
||||||
|
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
|
||||||
|
* Candidate methods are currently limited to public, no-arg methods named "close" or
|
||||||
|
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
|
||||||
|
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
|
||||||
|
* to the name of the inferred method. This constant serves as the default for the
|
||||||
|
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
|
||||||
|
* used in XML within the {@code <bean destroy-method="">} or {@code
|
||||||
|
* <beans default-destroy-method="">} attributes.
|
||||||
|
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
||||||
|
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
||||||
|
String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
|
||||||
|
if (destroyMethodName == null) {
|
||||||
|
destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||||
|
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
||||||
|
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
||||||
|
// Only perform destroy method inference or Closeable detection
|
||||||
|
// in case of the bean not explicitly implementing DisposableBean
|
||||||
|
destroyMethodName = null;
|
||||||
|
if (!(bean instanceof DisposableBean)) {
|
||||||
|
try {
|
||||||
|
destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException ex) {
|
||||||
|
try {
|
||||||
|
destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException ex2) {
|
||||||
|
// no candidate destroy method found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
|
||||||
}
|
}
|
||||||
return StringUtils.hasLength(destroyMethodName);
|
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -408,4 +388,25 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for all DestructionAwareBeanPostProcessors in the List.
|
||||||
|
* @param processors the List to search
|
||||||
|
* @return the filtered List of DestructionAwareBeanPostProcessors
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static List<DestructionAwareBeanPostProcessor> filterPostProcessors(
|
||||||
|
List<DestructionAwareBeanPostProcessor> processors, Object bean) {
|
||||||
|
|
||||||
|
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||||
|
if (!CollectionUtils.isEmpty(processors)) {
|
||||||
|
filteredPostProcessors = new ArrayList<>(processors.size());
|
||||||
|
for (DestructionAwareBeanPostProcessor processor : processors) {
|
||||||
|
if (processor.requiresDestruction(bean)) {
|
||||||
|
filteredPostProcessors.add(processor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredPostProcessors;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2020 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -86,6 +86,10 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||||
@Nullable
|
@Nullable
|
||||||
volatile Method factoryMethodToIntrospect;
|
volatile Method factoryMethodToIntrospect;
|
||||||
|
|
||||||
|
/** Package-visible field for caching a resolved destroy method name (also for inferred). */
|
||||||
|
@Nullable
|
||||||
|
volatile String resolvedDestroyMethodName;
|
||||||
|
|
||||||
/** Common lock for the four constructor fields below. */
|
/** Common lock for the four constructor fields below. */
|
||||||
final Object constructorArgumentLock = new Object();
|
final Object constructorArgumentLock = new Object();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue