diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
index 2fb1314512..a013c2bdce 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
@@ -74,7 +74,6 @@ import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
-import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
@@ -1789,11 +1788,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
if (mbd != null && bean.getClass() != NullBean.class) {
- String initMethodName = mbd.getInitMethodName();
- if (StringUtils.hasLength(initMethodName) &&
- !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
- !mbd.isExternallyManagedInitMethod(initMethodName)) {
- invokeCustomInitMethod(beanName, bean, mbd);
+ String[] initMethodNames = mbd.getInitMethodNames();
+ if (initMethodNames != null) {
+ for (String initMethodName : initMethodNames) {
+ if (StringUtils.hasLength(initMethodName) &&
+ !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
+ !mbd.isExternallyManagedInitMethod(initMethodName)) {
+ invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
+ }
+ }
}
}
}
@@ -1805,11 +1808,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* methods with arguments.
* @see #invokeInitMethods
*/
- protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd)
+ protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd, String initMethodName)
throws Throwable {
- String initMethodName = mbd.getInitMethodName();
- Assert.state(initMethodName != null, "No init method set");
Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java
index 847574dbd2..0176af001a 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -184,10 +184,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
private MethodOverrides methodOverrides = new MethodOverrides();
@Nullable
- private String initMethodName;
+ private String[] initMethodNames;
@Nullable
- private String destroyMethodName;
+ private String[] destroyMethodNames;
private boolean enforceInitMethod = true;
@@ -262,9 +262,9 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
setInstanceSupplier(originalAbd.getInstanceSupplier());
setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
- setInitMethodName(originalAbd.getInitMethodName());
+ setInitMethodNames(originalAbd.getInitMethodNames());
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
- setDestroyMethodName(originalAbd.getDestroyMethodName());
+ setDestroyMethodNames(originalAbd.getDestroyMethodNames());
setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod());
setSynthetic(originalAbd.isSynthetic());
setResource(originalAbd.getResource());
@@ -338,12 +338,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
setInstanceSupplier(otherAbd.getInstanceSupplier());
setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
- if (otherAbd.getInitMethodName() != null) {
- setInitMethodName(otherAbd.getInitMethodName());
+ if (otherAbd.getInitMethodNames() != null) {
+ setInitMethodNames(otherAbd.getInitMethodNames());
setEnforceInitMethod(otherAbd.isEnforceInitMethod());
}
- if (otherAbd.getDestroyMethodName() != null) {
- setDestroyMethodName(otherAbd.getDestroyMethodName());
+ if (otherAbd.getDestroyMethodNames() != null) {
+ setDestroyMethodNames(otherAbd.getDestroyMethodNames());
setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod());
}
setSynthetic(otherAbd.isSynthetic());
@@ -919,21 +919,41 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
}
/**
- * Set the name of the initializer method.
- *
The default is {@code null} in which case there is no initializer method.
+ * Specify the names of multiple initializer methods.
+ *
The default is {@code null} in which case there are no initializer methods.
+ * @since 6.0
+ * @see #setInitMethodName
*/
- @Override
- public void setInitMethodName(@Nullable String initMethodName) {
- this.initMethodName = initMethodName;
+ public void setInitMethodNames(@Nullable String... initMethodNames) {
+ this.initMethodNames = initMethodNames;
}
/**
- * Return the name of the initializer method.
+ * Return the names of the initializer methods.
+ * @since 6.0
+ */
+ @Nullable
+ public String[] getInitMethodNames() {
+ return this.initMethodNames;
+ }
+
+ /**
+ * Set the name of the initializer method.
+ *
The default is {@code null} in which case there is no initializer method.
+ * @see #setInitMethodNames
+ */
+ @Override
+ public void setInitMethodName(@Nullable String initMethodName) {
+ this.initMethodNames = (initMethodName != null ? new String[] {initMethodName} : null);
+ }
+
+ /**
+ * Return the name of the initializer method (the first one in case of multiple methods).
*/
@Override
@Nullable
public String getInitMethodName() {
- return this.initMethodName;
+ return (!ObjectUtils.isEmpty(this.initMethodNames) ? this.initMethodNames[0] : null);
}
/**
@@ -958,21 +978,41 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
}
/**
- * Set the name of the destroy method.
- *
The default is {@code null} in which case there is no destroy method.
+ * Specify the names of multiple destroy methods.
+ *
The default is {@code null} in which case there are no destroy methods.
+ * @since 6.0
+ * @see #setDestroyMethodName
*/
- @Override
- public void setDestroyMethodName(@Nullable String destroyMethodName) {
- this.destroyMethodName = destroyMethodName;
+ public void setDestroyMethodNames(@Nullable String... destroyMethodNames) {
+ this.destroyMethodNames = destroyMethodNames;
}
/**
- * Return the name of the destroy method.
+ * Return the names of the destroy methods.
+ * @since 6.0
+ */
+ @Nullable
+ public String[] getDestroyMethodNames() {
+ return this.destroyMethodNames;
+ }
+
+ /**
+ * Set the name of the destroy method.
+ *
The default is {@code null} in which case there is no destroy method.
+ * @see #setDestroyMethodNames
+ */
+ @Override
+ public void setDestroyMethodName(@Nullable String destroyMethodName) {
+ this.destroyMethodNames = (destroyMethodName != null ? new String[] {destroyMethodName} : null);
+ }
+
+ /**
+ * Return the name of the destroy method (the first one in case of multiple methods).
*/
@Override
@Nullable
public String getDestroyMethodName() {
- return this.destroyMethodName;
+ return (!ObjectUtils.isEmpty(this.destroyMethodNames) ? this.destroyMethodNames[0] : null);
}
/**
@@ -1189,9 +1229,9 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) &&
ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) &&
ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) &&
- ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName) &&
+ ObjectUtils.nullSafeEquals(this.initMethodNames, that.initMethodNames) &&
this.enforceInitMethod == that.enforceInitMethod &&
- ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName) &&
+ ObjectUtils.nullSafeEquals(this.destroyMethodNames, that.destroyMethodNames) &&
this.enforceDestroyMethod == that.enforceDestroyMethod &&
this.synthetic == that.synthetic &&
this.role == that.role &&
@@ -1241,8 +1281,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
sb.append("; primary=").append(this.primary);
sb.append("; factoryBeanName=").append(this.factoryBeanName);
sb.append("; factoryMethodName=").append(this.factoryMethodName);
- sb.append("; initMethodName=").append(this.initMethodName);
- sb.append("; destroyMethodName=").append(this.destroyMethodName);
+ sb.append("; initMethodNames=").append(this.initMethodNames);
+ sb.append("; destroyMethodNames=").append(this.destroyMethodNames);
if (this.resource != null) {
sb.append("; defined in ").append(this.resource.getDescription());
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
index 0f1b5ecd46..23354b6ccc 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
@@ -32,6 +32,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
@@ -51,7 +52,7 @@ import org.springframework.util.StringUtils;
* @see AbstractBeanFactory
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
- * @see AbstractBeanDefinition#getDestroyMethodName()
+ * @see AbstractBeanDefinition#getDestroyMethodNames()
*/
@SuppressWarnings("serial")
class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
@@ -76,10 +77,10 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private boolean invokeAutoCloseable;
@Nullable
- private String destroyMethodName;
+ private String[] destroyMethodNames;
@Nullable
- private transient Method destroyMethod;
+ private transient Method[] destroyMethods;
@Nullable
private final List beanPostProcessors;
@@ -103,36 +104,42 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.invokeDisposableBean = (bean instanceof DisposableBean &&
!beanDefinition.isExternallyManagedDestroyMethod(DESTROY_METHOD_NAME));
- String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
- if (destroyMethodName != null &&
- !(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodName)) &&
- !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
+ String[] destroyMethodNames = inferDestroyMethodsIfNecessary(bean, beanDefinition);
+ if (!ObjectUtils.isEmpty(destroyMethodNames) &&
+ !(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodNames[0])) &&
+ !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodNames[0])) {
- this.invokeAutoCloseable = (bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodName));
+ this.invokeAutoCloseable =
+ (bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodNames[0]));
if (!this.invokeAutoCloseable) {
- this.destroyMethodName = destroyMethodName;
- Method destroyMethod = determineDestroyMethod(destroyMethodName);
- if (destroyMethod == null) {
- if (beanDefinition.isEnforceDestroyMethod()) {
- throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
- destroyMethodName + "' on bean with name '" + beanName + "'");
- }
- }
- else {
- if (destroyMethod.getParameterCount() > 0) {
- Class>[] paramTypes = destroyMethod.getParameterTypes();
- if (paramTypes.length > 1) {
- 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 '" +
- beanName + "' has a non-boolean parameter - not supported as destroy method");
+ this.destroyMethodNames = destroyMethodNames;
+ Method[] destroyMethods = new Method[destroyMethodNames.length];
+ for (int i = 0; i < destroyMethodNames.length; i++) {
+ String destroyMethodName = destroyMethodNames[i];
+ Method destroyMethod = determineDestroyMethod(destroyMethodName);
+ if (destroyMethod == null) {
+ if (beanDefinition.isEnforceDestroyMethod()) {
+ throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
+ destroyMethodName + "' on bean with name '" + beanName + "'");
}
}
- destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod, bean.getClass());
+ else {
+ if (destroyMethod.getParameterCount() > 0) {
+ Class>[] paramTypes = destroyMethod.getParameterTypes();
+ if (paramTypes.length > 1) {
+ 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 '" +
+ beanName + "' has a non-boolean parameter - not supported as destroy method");
+ }
+ }
+ destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod, bean.getClass());
+ }
+ destroyMethods[i] = destroyMethod;
}
- this.destroyMethod = destroyMethod;
+ this.destroyMethods = destroyMethods;
}
}
@@ -158,7 +165,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
* Create a new DisposableBeanAdapter for the given bean.
*/
private DisposableBeanAdapter(Object bean, String beanName, boolean nonPublicAccessAllowed,
- boolean invokeDisposableBean, boolean invokeAutoCloseable, @Nullable String destroyMethodName,
+ boolean invokeDisposableBean, boolean invokeAutoCloseable, @Nullable String[] destroyMethodNames,
@Nullable List postProcessors) {
this.bean = bean;
@@ -166,7 +173,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.nonPublicAccessAllowed = nonPublicAccessAllowed;
this.invokeDisposableBean = invokeDisposableBean;
this.invokeAutoCloseable = invokeAutoCloseable;
- this.destroyMethodName = destroyMethodName;
+ this.destroyMethodNames = destroyMethodNames;
this.beanPostProcessors = postProcessors;
}
@@ -219,13 +226,18 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
}
- else if (this.destroyMethod != null) {
- invokeCustomDestroyMethod(this.destroyMethod);
+ else if (this.destroyMethods != null) {
+ for (Method destroyMethod : this.destroyMethods) {
+ invokeCustomDestroyMethod(destroyMethod);
+ }
}
- else if (this.destroyMethodName != null) {
- Method destroyMethod = determineDestroyMethod(this.destroyMethodName);
- if (destroyMethod != null) {
- invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass()));
+ else if (this.destroyMethodNames != null) {
+ for (String destroyMethodName: this.destroyMethodNames) {
+ Method destroyMethod = determineDestroyMethod(destroyMethodName);
+ if (destroyMethod != null) {
+ invokeCustomDestroyMethod(
+ ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass()));
+ }
}
}
}
@@ -255,14 +267,14 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
* for a method with a single boolean argument (passing in "true",
* assuming a "force" parameter), else logging an error.
*/
- private void invokeCustomDestroyMethod(final Method destroyMethod) {
+ private void invokeCustomDestroyMethod(Method destroyMethod) {
int paramCount = destroyMethod.getParameterCount();
final Object[] args = new Object[paramCount];
if (paramCount == 1) {
args[0] = Boolean.TRUE;
}
if (logger.isTraceEnabled()) {
- logger.trace("Invoking custom destroy method '" + this.destroyMethodName +
+ logger.trace("Invoking custom destroy method '" + destroyMethod.getName() +
"' on bean with name '" + this.beanName + "'");
}
try {
@@ -270,7 +282,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
destroyMethod.invoke(this.bean, args);
}
catch (InvocationTargetException ex) {
- String msg = "Custom destroy method '" + this.destroyMethodName + "' on bean with name '" +
+ String msg = "Custom destroy method '" + destroyMethod.getName() + "' on bean with name '" +
this.beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex.getTargetException());
@@ -280,7 +292,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
catch (Throwable ex) {
- logger.warn("Failed to invoke custom destroy method '" + this.destroyMethodName +
+ logger.warn("Failed to invoke custom destroy method '" + destroyMethod.getName() +
"' on bean with name '" + this.beanName + "'", ex);
}
}
@@ -302,7 +314,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
return new DisposableBeanAdapter(
this.bean, this.beanName, this.nonPublicAccessAllowed, this.invokeDisposableBean,
- this.invokeAutoCloseable, this.destroyMethodName, serializablePostProcessors);
+ this.invokeAutoCloseable, this.destroyMethodNames, serializablePostProcessors);
}
@@ -312,7 +324,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
* @param beanDefinition the corresponding bean definition
*/
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
- return (bean instanceof DisposableBean || inferDestroyMethodIfNecessary(bean, beanDefinition) != null);
+ return (bean instanceof DisposableBean || inferDestroyMethodsIfNecessary(bean, beanDefinition) != null);
}
@@ -330,7 +342,12 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
* interfaces, reflectively calling the "close" method on implementing beans as well.
*/
@Nullable
- private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
+ private static String[] inferDestroyMethodsIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
+ String[] destroyMethodNames = beanDefinition.getDestroyMethodNames();
+ if (destroyMethodNames != null && destroyMethodNames.length > 1) {
+ return destroyMethodNames;
+ }
+
String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
if (destroyMethodName == null) {
destroyMethodName = beanDefinition.getDestroyMethodName();
@@ -361,7 +378,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
}
- return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
+ return (StringUtils.hasLength(destroyMethodName) ? new String[] {destroyMethodName} : null);
}
/**
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
index db7454073c..accf86ef05 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
@@ -22,6 +22,7 @@ import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.text.NumberFormat;
import java.text.ParseException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
@@ -2333,6 +2334,19 @@ class DefaultListableBeanFactoryTests {
assertThat(tb2.getBeanName()).isEqualTo("myBeanName");
}
+ @Test
+ void multipleInitAndDestroyMethods() {
+ RootBeanDefinition bd = new RootBeanDefinition(BeanWithInitAndDestroyMethods.class);
+ bd.setInitMethodNames("init1", "init2");
+ bd.setDestroyMethodNames("destroy2", "destroy1");
+ lbf.registerBeanDefinition("test", bd);
+ BeanWithInitAndDestroyMethods bean = lbf.getBean("test", BeanWithInitAndDestroyMethods.class);
+ assertThat(bean.initMethods).containsExactly("init", "init1", "init2");
+ assertThat(bean.destroyMethods).isEmpty();
+ lbf.destroySingletons();
+ assertThat(bean.destroyMethods).containsExactly("destroy", "destroy2", "destroy1");
+ }
+
@Test
void beanPostProcessorWithWrappedObjectAndDisposableBean() {
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDisposableBean.class);
@@ -2758,9 +2772,42 @@ class DefaultListableBeanFactoryTests {
}
+ static class BeanWithInitAndDestroyMethods implements InitializingBean, DisposableBean {
+
+ final List initMethods = new ArrayList<>();
+ final List destroyMethods = new ArrayList<>();
+
+ @Override
+ public void afterPropertiesSet() {
+ initMethods.add("init");
+ }
+
+ void init1() {
+ initMethods.add("init1");
+ }
+
+ void init2() {
+ initMethods.add("init2");
+ }
+
+ @Override
+ public void destroy() {
+ destroyMethods.add("destroy");
+ }
+
+ void destroy1() {
+ destroyMethods.add("destroy1");
+ }
+
+ void destroy2() {
+ destroyMethods.add("destroy2");
+ }
+ }
+
+
public static class BeanWithDisposableBean implements DisposableBean {
- private static boolean closed;
+ static boolean closed;
@Override
public void destroy() {
@@ -2771,7 +2818,7 @@ class DefaultListableBeanFactoryTests {
public static class BeanWithCloseable implements Closeable {
- private static boolean closed;
+ static boolean closed;
@Override
public void close() {
@@ -2788,7 +2835,7 @@ class DefaultListableBeanFactoryTests {
public static class BeanWithDestroyMethod extends BaseClassWithDestroyMethod {
- private static int closeCount = 0;
+ static int closeCount = 0;
@SuppressWarnings("unused")
private BeanWithDestroyMethod inner;
diff --git a/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java b/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java
index 39772475c0..949da72371 100644
--- a/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -510,7 +510,7 @@ public class ScriptFactoryPostProcessor implements SmartInstantiationAwareBeanPo
Signature signature = new Signature(setterName, Type.VOID_TYPE, new Type[] {Type.getType(propertyType)});
maker.add(signature, new Type[0]);
}
- if (bd.getInitMethodName() != null) {
+ if (StringUtils.hasText(bd.getInitMethodName())) {
Signature signature = new Signature(bd.getInitMethodName(), Type.VOID_TYPE, new Type[0]);
maker.add(signature, new Type[0]);
}
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java b/spring-context/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java
index 82caf5254e..821fffffcf 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/Spr3775InitDestroyLifecycleTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,8 +22,6 @@ import java.util.List;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.DisposableBean;
@@ -35,15 +33,12 @@ import org.springframework.util.ObjectUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
- *
- * JUnit-3.8-based unit test which verifies expected init and
- * destroy bean lifecycle behavior as requested in init and destroy
+ * bean lifecycle behavior as requested in
+ * SPR-3775.
- *
- *
- * Specifically, combinations of the following are tested:
- *
+ *
+ * Specifically, combinations of the following are tested:
*
* - {@link InitializingBean} & {@link DisposableBean} interfaces
* - Custom {@link RootBeanDefinition#getInitMethodName() init} &
@@ -57,26 +52,17 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class Spr3775InitDestroyLifecycleTests {
- private static final Log logger = LogFactory.getLog(Spr3775InitDestroyLifecycleTests.class);
-
- /** LIFECYCLE_TEST_BEAN. */
private static final String LIFECYCLE_TEST_BEAN = "lifecycleTestBean";
- private void debugMethods(Class> clazz, String category, List methodNames) {
- if (logger.isDebugEnabled()) {
- logger.debug(clazz.getSimpleName() + ": " + category + ": " + methodNames);
- }
+ private void assertMethodOrdering(String category, List expectedMethods, List actualMethods) {
+ assertThat(ObjectUtils.nullSafeEquals(expectedMethods, actualMethods)).
+ as("Verifying " + category + ": expected<" + expectedMethods + "> but got<" + actualMethods + ">.").isTrue();
}
- private void assertMethodOrdering(Class> clazz, String category, List expectedMethods,
- List actualMethods) {
- debugMethods(clazz, category, actualMethods);
- assertThat(ObjectUtils.nullSafeEquals(expectedMethods, actualMethods)).as("Verifying " + category + ": expected<" + expectedMethods + "> but got<" + actualMethods + ">.").isTrue();
- }
+ private DefaultListableBeanFactory createBeanFactoryAndRegisterBean(
+ Class> beanClass, String initMethodName, String destroyMethodName) {
- private DefaultListableBeanFactory createBeanFactoryAndRegisterBean(final Class> beanClass,
- final String initMethodName, final String destroyMethodName) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setInitMethodName(initMethodName);
@@ -88,75 +74,77 @@ public class Spr3775InitDestroyLifecycleTests {
@Test
public void testInitDestroyMethods() {
- final Class> beanClass = InitDestroyBean.class;
- final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass,
+ Class> beanClass = InitDestroyBean.class;
+ DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass,
"afterPropertiesSet", "destroy");
- final InitDestroyBean bean = (InitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
- assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods);
+ InitDestroyBean bean = (InitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
+ assertMethodOrdering("init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods);
beanFactory.destroySingletons();
- assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy"), bean.destroyMethods);
+ assertMethodOrdering("destroy-methods", Arrays.asList("destroy"), bean.destroyMethods);
}
@Test
public void testInitializingDisposableInterfaces() {
- final Class> beanClass = CustomInitializingDisposableBean.class;
- final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit",
+ Class> beanClass = CustomInitializingDisposableBean.class;
+ DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit",
"customDestroy");
- final CustomInitializingDisposableBean bean = (CustomInitializingDisposableBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
- assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet", "customInit"),
+ CustomInitializingDisposableBean bean = (CustomInitializingDisposableBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
+ assertMethodOrdering("init-methods", Arrays.asList("afterPropertiesSet", "customInit"),
bean.initMethods);
beanFactory.destroySingletons();
- assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy", "customDestroy"),
+ assertMethodOrdering("destroy-methods", Arrays.asList("destroy", "customDestroy"),
bean.destroyMethods);
}
@Test
public void testInitializingDisposableInterfacesWithShadowedMethods() {
- final Class> beanClass = InitializingDisposableWithShadowedMethodsBean.class;
- final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass,
+ Class> beanClass = InitializingDisposableWithShadowedMethodsBean.class;
+ DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass,
"afterPropertiesSet", "destroy");
- final InitializingDisposableWithShadowedMethodsBean bean = (InitializingDisposableWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
- assertMethodOrdering(beanClass, "init-methods", Arrays.asList("InitializingBean.afterPropertiesSet"),
+ InitializingDisposableWithShadowedMethodsBean bean =
+ (InitializingDisposableWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
+ assertMethodOrdering("init-methods", Arrays.asList("InitializingBean.afterPropertiesSet"),
bean.initMethods);
beanFactory.destroySingletons();
- assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("DisposableBean.destroy"), bean.destroyMethods);
+ assertMethodOrdering("destroy-methods", Arrays.asList("DisposableBean.destroy"), bean.destroyMethods);
}
@Test
public void testJsr250Annotations() {
- final Class> beanClass = CustomAnnotatedInitDestroyBean.class;
- final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit",
+ Class> beanClass = CustomAnnotatedInitDestroyBean.class;
+ DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit",
"customDestroy");
- final CustomAnnotatedInitDestroyBean bean = (CustomAnnotatedInitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
- assertMethodOrdering(beanClass, "init-methods", Arrays.asList("postConstruct", "afterPropertiesSet",
+ CustomAnnotatedInitDestroyBean bean = (CustomAnnotatedInitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
+ assertMethodOrdering("init-methods", Arrays.asList("postConstruct", "afterPropertiesSet",
"customInit"), bean.initMethods);
beanFactory.destroySingletons();
- assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("preDestroy", "destroy", "customDestroy"),
+ assertMethodOrdering("destroy-methods", Arrays.asList("preDestroy", "destroy", "customDestroy"),
bean.destroyMethods);
}
@Test
public void testJsr250AnnotationsWithShadowedMethods() {
- final Class> beanClass = CustomAnnotatedInitDestroyWithShadowedMethodsBean.class;
- final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit",
+ Class> beanClass = CustomAnnotatedInitDestroyWithShadowedMethodsBean.class;
+ DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit",
"customDestroy");
- final CustomAnnotatedInitDestroyWithShadowedMethodsBean bean = (CustomAnnotatedInitDestroyWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
- assertMethodOrdering(beanClass, "init-methods",
+ CustomAnnotatedInitDestroyWithShadowedMethodsBean bean =
+ (CustomAnnotatedInitDestroyWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
+ assertMethodOrdering("init-methods",
Arrays.asList("@PostConstruct.afterPropertiesSet", "customInit"), bean.initMethods);
beanFactory.destroySingletons();
- assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("@PreDestroy.destroy", "customDestroy"),
+ assertMethodOrdering("destroy-methods", Arrays.asList("@PreDestroy.destroy", "customDestroy"),
bean.destroyMethods);
}
@Test
public void testAllLifecycleMechanismsAtOnce() {
- final Class> beanClass = AllInOneBean.class;
- final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass,
+ Class> beanClass = AllInOneBean.class;
+ DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass,
"afterPropertiesSet", "destroy");
- final AllInOneBean bean = (AllInOneBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
- assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods);
+ AllInOneBean bean = (AllInOneBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN);
+ assertMethodOrdering("init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods);
beanFactory.destroySingletons();
- assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy"), bean.destroyMethods);
+ assertMethodOrdering("destroy-methods", Arrays.asList("destroy"), bean.destroyMethods);
}
@@ -165,7 +153,6 @@ public class Spr3775InitDestroyLifecycleTests {
final List initMethods = new ArrayList<>();
final List destroyMethods = new ArrayList<>();
-
public void afterPropertiesSet() throws Exception {
this.initMethods.add("afterPropertiesSet");
}
@@ -175,8 +162,9 @@ public class Spr3775InitDestroyLifecycleTests {
}
}
- public static class InitializingDisposableWithShadowedMethodsBean extends InitDestroyBean implements
- InitializingBean, DisposableBean {
+
+ public static class InitializingDisposableWithShadowedMethodsBean extends InitDestroyBean
+ implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
@@ -255,14 +243,14 @@ public class Spr3775InitDestroyLifecycleTests {
final List initMethods = new ArrayList<>();
final List destroyMethods = new ArrayList<>();
- @Override
@PostConstruct
+ @Override
public void afterPropertiesSet() throws Exception {
this.initMethods.add("afterPropertiesSet");
}
- @Override
@PreDestroy
+ @Override
public void destroy() throws Exception {
this.destroyMethods.add("destroy");
}