Skip to content

Commit dff2c84

Browse files
committed
Clarify destroy method suppression for DisposableBean vs (Auto)Closeable
Issue: SPR-16078
1 parent 17fb4fe commit dff2c84

File tree

2 files changed

+52
-15
lines changed

2 files changed

+52
-15
lines changed

spring-context/src/main/java/org/springframework/context/annotation/Bean.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -157,8 +157,8 @@
157157
*
158158
* <pre class="code">
159159
* &#064;Bean
160-
* public static PropertyPlaceholderConfigurer ppc() {
161-
* // instantiate, configure and return ppc ...
160+
* public static PropertySourcesPlaceholderConfigurer pspc() {
161+
* // instantiate, configure and return pspc ...
162162
* }
163163
* </pre>
164164
*
@@ -228,6 +228,8 @@
228228
* Not commonly used, given that the method may be called programmatically directly
229229
* within the body of a Bean-annotated method.
230230
* <p>The default value is {@code ""}, indicating no init method to be called.
231+
* @see org.springframework.beans.factory.InitializingBean
232+
* @see org.springframework.context.ConfigurableApplicationContext#refresh()
231233
*/
232234
String initMethod() default "";
233235

@@ -248,12 +250,14 @@
248250
* creation time).
249251
* <p>To disable destroy method inference for a particular {@code @Bean}, specify an
250252
* empty string as the value, e.g. {@code @Bean(destroyMethod="")}. Note that the
251-
* {@link org.springframework.beans.factory.DisposableBean} and the
252-
* {@link java.io.Closeable}/{@link java.lang.AutoCloseable} interfaces will
253-
* nevertheless get detected and the corresponding destroy/close method invoked.
253+
* {@link org.springframework.beans.factory.DisposableBean} callback interface will
254+
* nevertheless get detected and the corresponding destroy method invoked: In other
255+
* words, {@code destroyMethod=""} only affects custom close/shutdown methods and
256+
* {@link java.io.Closeable}/{@link java.lang.AutoCloseable} declared close methods.
254257
* <p>Note: Only invoked on beans whose lifecycle is under the full control of the
255258
* factory, which is always the case for singletons but not guaranteed for any
256259
* other scope.
260+
* @see org.springframework.beans.factory.DisposableBean
257261
* @see org.springframework.context.ConfigurableApplicationContext#close()
258262
*/
259263
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;

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

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,10 +17,10 @@
1717
package org.springframework.context.annotation;
1818

1919
import java.io.Closeable;
20-
import java.io.IOException;
2120

2221
import org.junit.Test;
2322

23+
import org.springframework.beans.factory.DisposableBean;
2424
import org.springframework.context.ConfigurableApplicationContext;
2525
import org.springframework.context.support.GenericXmlApplicationContext;
2626

@@ -36,8 +36,7 @@ public class DestroyMethodInferenceTests {
3636

3737
@Test
3838
public void beanMethods() {
39-
ConfigurableApplicationContext ctx =
40-
new AnnotationConfigApplicationContext(Config.class);
39+
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
4140
WithExplicitDestroyMethod c0 = ctx.getBean(WithExplicitDestroyMethod.class);
4241
WithLocalCloseMethod c1 = ctx.getBean("c1", WithLocalCloseMethod.class);
4342
WithLocalCloseMethod c2 = ctx.getBean("c2", WithLocalCloseMethod.class);
@@ -47,6 +46,7 @@ public void beanMethods() {
4746
WithNoCloseMethod c6 = ctx.getBean("c6", WithNoCloseMethod.class);
4847
WithLocalShutdownMethod c7 = ctx.getBean("c7", WithLocalShutdownMethod.class);
4948
WithInheritedCloseMethod c8 = ctx.getBean("c8", WithInheritedCloseMethod.class);
49+
WithDisposableBean c9 = ctx.getBean("c9", WithDisposableBean.class);
5050

5151
assertThat(c0.closed, is(false));
5252
assertThat(c1.closed, is(false));
@@ -57,6 +57,7 @@ public void beanMethods() {
5757
assertThat(c6.closed, is(false));
5858
assertThat(c7.closed, is(false));
5959
assertThat(c8.closed, is(false));
60+
assertThat(c9.closed, is(false));
6061
ctx.close();
6162
assertThat("c0", c0.closed, is(true));
6263
assertThat("c1", c1.closed, is(true));
@@ -67,6 +68,7 @@ public void beanMethods() {
6768
assertThat("c6", c6.closed, is(false));
6869
assertThat("c7", c7.closed, is(true));
6970
assertThat("c8", c8.closed, is(false));
71+
assertThat("c9", c9.closed, is(true));
7072
}
7173

7274
@Test
@@ -91,9 +93,11 @@ public void xml() {
9193
assertThat(x8.closed, is(false));
9294
}
9395

96+
9497
@Configuration
9598
static class Config {
96-
@Bean(destroyMethod="explicitClose")
99+
100+
@Bean(destroyMethod = "explicitClose")
97101
public WithExplicitDestroyMethod c0() {
98102
return new WithExplicitDestroyMethod();
99103
}
@@ -118,12 +122,12 @@ public Closeable c4() {
118122
return new WithInheritedCloseMethod();
119123
}
120124

121-
@Bean(destroyMethod="other")
125+
@Bean(destroyMethod = "other")
122126
public WithInheritedCloseMethod c5() {
123127
return new WithInheritedCloseMethod() {
124128
@Override
125-
public void close() throws IOException {
126-
throw new RuntimeException("close() should not be called");
129+
public void close() {
130+
throw new IllegalStateException("close() should not be called");
127131
}
128132
@SuppressWarnings("unused")
129133
public void other() {
@@ -146,37 +150,66 @@ public WithLocalShutdownMethod c7() {
146150
public WithInheritedCloseMethod c8() {
147151
return new WithInheritedCloseMethod();
148152
}
153+
154+
@Bean(destroyMethod = "")
155+
public WithDisposableBean c9() {
156+
return new WithDisposableBean();
157+
}
149158
}
150159

151160

152161
static class WithExplicitDestroyMethod {
162+
153163
boolean closed = false;
164+
154165
public void explicitClose() {
155166
closed = true;
156167
}
157168
}
158169

170+
159171
static class WithLocalCloseMethod {
172+
160173
boolean closed = false;
174+
161175
public void close() {
162176
closed = true;
163177
}
164178
}
165179

180+
166181
static class WithInheritedCloseMethod implements Closeable {
182+
183+
boolean closed = false;
184+
185+
@Override
186+
public void close() {
187+
closed = true;
188+
}
189+
}
190+
191+
192+
static class WithDisposableBean implements DisposableBean {
193+
167194
boolean closed = false;
195+
168196
@Override
169-
public void close() throws IOException {
197+
public void destroy() {
170198
closed = true;
171199
}
172200
}
173201

202+
174203
static class WithNoCloseMethod {
204+
175205
boolean closed = false;
176206
}
177207

208+
178209
static class WithLocalShutdownMethod {
210+
179211
boolean closed = false;
212+
180213
public void shutdown() {
181214
closed = true;
182215
}

0 commit comments

Comments
 (0)