Browse Source

Backported tests for bean-derived (Auto)Closeable.close() method

See gh-27504
pull/28694/head
Juergen Hoeller 4 years ago
parent
commit
790d56dd18
  1. 16
      spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
  2. 45
      spring-context/src/test/java/org/springframework/context/annotation/DestroyMethodInferenceTests.java
  3. 8
      spring-context/src/test/resources/org/springframework/context/annotation/DestroyMethodInferenceTests-context.xml

16
spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java

@ -62,6 +62,8 @@ import org.springframework.util.StringUtils;
@SuppressWarnings("serial") @SuppressWarnings("serial")
class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private static final String DESTROY_METHOD_NAME = "destroy";
private static final String CLOSE_METHOD_NAME = "close"; private static final String CLOSE_METHOD_NAME = "close";
private static final String SHUTDOWN_METHOD_NAME = "shutdown"; private static final String SHUTDOWN_METHOD_NAME = "shutdown";
@ -104,13 +106,16 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
Assert.notNull(bean, "Disposable bean must not be null"); Assert.notNull(bean, "Disposable bean must not be null");
this.bean = bean; this.bean = bean;
this.beanName = beanName; this.beanName = beanName;
this.invokeDisposableBean = this.invokeDisposableBean = (bean instanceof DisposableBean &&
(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy")); !beanDefinition.isExternallyManagedDestroyMethod(DESTROY_METHOD_NAME));
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed(); this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
this.acc = acc; this.acc = acc;
String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition); String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) && if (destroyMethodName != null &&
!(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodName)) &&
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
this.destroyMethodName = destroyMethodName; this.destroyMethodName = destroyMethodName;
Method destroyMethod = determineDestroyMethod(destroyMethodName); Method destroyMethod = determineDestroyMethod(destroyMethodName);
if (destroyMethod == null) { if (destroyMethod == null) {
@ -135,6 +140,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
} }
this.destroyMethod = destroyMethod; this.destroyMethod = destroyMethod;
} }
this.beanPostProcessors = filterPostProcessors(postProcessors, bean); this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
} }
@ -349,8 +355,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
destroyMethodName = beanDefinition.getDestroyMethodName(); destroyMethodName = beanDefinition.getDestroyMethodName();
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) || if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
(destroyMethodName == null && bean instanceof AutoCloseable)) { (destroyMethodName == null && bean instanceof AutoCloseable)) {
// Only perform destroy method inference or Closeable detection // Only perform destroy method inference in case of the bean
// in case of the bean not explicitly implementing DisposableBean // not explicitly implementing the DisposableBean interface
destroyMethodName = null; destroyMethodName = null;
if (!(bean instanceof DisposableBean)) { if (!(bean instanceof DisposableBean)) {
try { try {

45
spring-context/src/test/java/org/springframework/context/annotation/DestroyMethodInferenceTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 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.
@ -26,7 +26,6 @@ import org.springframework.context.support.GenericXmlApplicationContext;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Chris Beams * @author Chris Beams
* @author Juergen Hoeller * @author Juergen Hoeller
@ -47,6 +46,7 @@ public class DestroyMethodInferenceTests {
WithLocalShutdownMethod c7 = ctx.getBean("c7", WithLocalShutdownMethod.class); WithLocalShutdownMethod c7 = ctx.getBean("c7", WithLocalShutdownMethod.class);
WithInheritedCloseMethod c8 = ctx.getBean("c8", WithInheritedCloseMethod.class); WithInheritedCloseMethod c8 = ctx.getBean("c8", WithInheritedCloseMethod.class);
WithDisposableBean c9 = ctx.getBean("c9", WithDisposableBean.class); WithDisposableBean c9 = ctx.getBean("c9", WithDisposableBean.class);
WithAutoCloseable c10 = ctx.getBean("c10", WithAutoCloseable.class);
assertThat(c0.closed).as("c0").isFalse(); assertThat(c0.closed).as("c0").isFalse();
assertThat(c1.closed).as("c1").isFalse(); assertThat(c1.closed).as("c1").isFalse();
@ -58,6 +58,8 @@ public class DestroyMethodInferenceTests {
assertThat(c7.closed).as("c7").isFalse(); assertThat(c7.closed).as("c7").isFalse();
assertThat(c8.closed).as("c8").isFalse(); assertThat(c8.closed).as("c8").isFalse();
assertThat(c9.closed).as("c9").isFalse(); assertThat(c9.closed).as("c9").isFalse();
assertThat(c10.closed).as("c10").isFalse();
ctx.close(); ctx.close();
assertThat(c0.closed).as("c0").isTrue(); assertThat(c0.closed).as("c0").isTrue();
assertThat(c1.closed).as("c1").isTrue(); assertThat(c1.closed).as("c1").isTrue();
@ -69,6 +71,7 @@ public class DestroyMethodInferenceTests {
assertThat(c7.closed).as("c7").isTrue(); assertThat(c7.closed).as("c7").isTrue();
assertThat(c8.closed).as("c8").isFalse(); assertThat(c8.closed).as("c8").isFalse();
assertThat(c9.closed).as("c9").isTrue(); assertThat(c9.closed).as("c9").isTrue();
assertThat(c10.closed).as("c10").isTrue();
} }
@Test @Test
@ -80,21 +83,29 @@ public class DestroyMethodInferenceTests {
WithLocalCloseMethod x3 = ctx.getBean("x3", WithLocalCloseMethod.class); WithLocalCloseMethod x3 = ctx.getBean("x3", WithLocalCloseMethod.class);
WithNoCloseMethod x4 = ctx.getBean("x4", WithNoCloseMethod.class); WithNoCloseMethod x4 = ctx.getBean("x4", WithNoCloseMethod.class);
WithInheritedCloseMethod x8 = ctx.getBean("x8", WithInheritedCloseMethod.class); WithInheritedCloseMethod x8 = ctx.getBean("x8", WithInheritedCloseMethod.class);
WithDisposableBean x9 = ctx.getBean("x9", WithDisposableBean.class);
WithAutoCloseable x10 = ctx.getBean("x10", WithAutoCloseable.class);
assertThat(x1.closed).isFalse(); assertThat(x1.closed).isFalse();
assertThat(x2.closed).isFalse(); assertThat(x2.closed).isFalse();
assertThat(x3.closed).isFalse(); assertThat(x3.closed).isFalse();
assertThat(x4.closed).isFalse(); assertThat(x4.closed).isFalse();
assertThat(x8.closed).isFalse();
assertThat(x9.closed).isFalse();
assertThat(x10.closed).isFalse();
ctx.close(); ctx.close();
assertThat(x1.closed).isFalse(); assertThat(x1.closed).isFalse();
assertThat(x2.closed).isTrue(); assertThat(x2.closed).isTrue();
assertThat(x3.closed).isTrue(); assertThat(x3.closed).isTrue();
assertThat(x4.closed).isFalse(); assertThat(x4.closed).isFalse();
assertThat(x8.closed).isFalse(); assertThat(x8.closed).isFalse();
assertThat(x9.closed).isTrue();
assertThat(x10.closed).isTrue();
} }
@Configuration @Configuration(proxyBeanMethods = false)
static class Config { static class Config {
@Bean(destroyMethod = "explicitClose") @Bean(destroyMethod = "explicitClose")
@ -155,6 +166,11 @@ public class DestroyMethodInferenceTests {
public WithDisposableBean c9() { public WithDisposableBean c9() {
return new WithDisposableBean(); return new WithDisposableBean();
} }
@Bean
public WithAutoCloseable c10() {
return new WithAutoCloseable();
}
} }
@ -189,28 +205,39 @@ public class DestroyMethodInferenceTests {
} }
static class WithDisposableBean implements DisposableBean { static class WithNoCloseMethod {
boolean closed = false; boolean closed = false;
}
@Override
public void destroy() { static class WithLocalShutdownMethod {
boolean closed = false;
public void shutdown() {
closed = true; closed = true;
} }
} }
static class WithNoCloseMethod { static class WithDisposableBean implements DisposableBean {
boolean closed = false; boolean closed = false;
@Override
public void destroy() {
closed = true;
}
} }
static class WithLocalShutdownMethod { static class WithAutoCloseable implements AutoCloseable {
boolean closed = false; boolean closed = false;
public void shutdown() { @Override
public void close() {
closed = true; closed = true;
} }
} }

8
spring-context/src/test/resources/org/springframework/context/annotation/DestroyMethodInferenceTests-context.xml

@ -15,10 +15,16 @@
class="org.springframework.context.annotation.DestroyMethodInferenceTests.WithInheritedCloseMethod" class="org.springframework.context.annotation.DestroyMethodInferenceTests.WithInheritedCloseMethod"
destroy-method=""/> destroy-method=""/>
<bean id="x9"
class="org.springframework.context.annotation.DestroyMethodInferenceTests.WithDisposableBean"
destroy-method=""/>
<bean id="x10"
class="org.springframework.context.annotation.DestroyMethodInferenceTests.WithAutoCloseable"/>
<beans default-destroy-method="(inferred)"> <beans default-destroy-method="(inferred)">
<bean id="x3" <bean id="x3"
class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithLocalCloseMethod"/> class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithLocalCloseMethod"/>
<bean id="x4" <bean id="x4"
class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithNoCloseMethod"/> class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithNoCloseMethod"/>
</beans> </beans>

Loading…
Cancel
Save