Browse Source
Anywhere the value of a destroy method may be expressed, specifying
the value "(inferred)" now indicates that the container should attempt
to automatically discover a destroy method. This functionality is
currently limited to detecting public, no-arg methods named 'close';
this is particularly useful for commonly used types such as Hibernate
SessionFactory most JDBC DataSource implementations, JMS connection
factories, and so forth.
This special value is captured as the constant
AbstractBeanDefinition#INFER_METHOD, which in turn serves as the default
value of the @Bean#destroyMethod attribute.
For example in the following case
@Bean
public BasicDataSource dataSource() { ... }
the container will automatically detect BasicDataSource#close and invoke
it when the enclosing ApplicationContext is closed. This is exactly
equivalent to
@Bean(destroyMethod="(inferred)")
public BasicDataSource dataSource() { ... }
A user may override this inference-by-default convention simply by
specifying a different method
@Bean(destroyMethod="myClose")
public MyBasicDataSource dataSource() { ... }
or, in the case of a bean that has an otherwise inferrable 'close'
method, but the user wishes to disable handling it entirely, an empty
string may be specified
@Bean(destroyMethod="")
public MyBasicDataSource dataSource() { ... }
The special destroy method name "(inferred)" may also be specified in
an XML context, e.g.
<bean destroy-method="(inferred)">
or
<beans default-destroy-method="(inferred)">
Note that "(inferred)" is the default value for @Bean#destroyMethod,
but NOT for the destroy-method and default-destroy-method attributes
in the spring-beans XML schema.
The principal reason for introducing this feature is to avoid forcing
@Configuration class users to type destroyMethod="close" every time a
closeable bean is configured. This kind of boilerplate is easily
forgotten, and this simple convention means the right thing is done
by default, while allowing the user full control over customization or
disablement in special cases.
Issue: SPR-8751
pull/7/head
6 changed files with 223 additions and 11 deletions
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns:context="http://www.springframework.org/schema/context" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans |
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd |
||||
http://www.springframework.org/schema/context |
||||
http://www.springframework.org/schema/context/spring-context-3.1.xsd"> |
||||
|
||||
<bean id="x1" |
||||
class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithLocalCloseMethod"/> |
||||
|
||||
<bean id="x2" |
||||
class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithLocalCloseMethod" |
||||
destroy-method="(inferred)"/> |
||||
|
||||
<beans default-destroy-method="(inferred)"> |
||||
<bean id="x3" |
||||
class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithLocalCloseMethod"/> |
||||
|
||||
<bean id="x4" |
||||
class="org.springframework.context.annotation.DestroyMethodInferenceTests$WithNoCloseMethod"/> |
||||
</beans> |
||||
|
||||
</beans> |
||||
@ -0,0 +1,151 @@
@@ -0,0 +1,151 @@
|
||||
/* |
||||
* Copyright 2002-2011 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.context.annotation; |
||||
|
||||
import static org.hamcrest.CoreMatchers.is; |
||||
import static org.junit.Assert.assertThat; |
||||
|
||||
import java.io.Closeable; |
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.context.support.GenericXmlApplicationContext; |
||||
|
||||
public class DestroyMethodInferenceTests { |
||||
|
||||
@Test |
||||
public void beanMethods() { |
||||
ConfigurableApplicationContext ctx = |
||||
new AnnotationConfigApplicationContext(Config.class); |
||||
WithExplicitDestroyMethod c0 = ctx.getBean(WithExplicitDestroyMethod.class); |
||||
WithLocalCloseMethod c1 = ctx.getBean("c1", WithLocalCloseMethod.class); |
||||
WithLocalCloseMethod c2 = ctx.getBean("c2", WithLocalCloseMethod.class); |
||||
WithInheritedCloseMethod c3 = ctx.getBean("c3", WithInheritedCloseMethod.class); |
||||
WithInheritedCloseMethod c4 = ctx.getBean("c4", WithInheritedCloseMethod.class); |
||||
WithInheritedCloseMethod c5 = ctx.getBean("c5", WithInheritedCloseMethod.class); |
||||
WithNoCloseMethod c6 = ctx.getBean("c6", WithNoCloseMethod.class); |
||||
|
||||
assertThat(c0.closed, is(false)); |
||||
assertThat(c1.closed, is(false)); |
||||
assertThat(c2.closed, is(false)); |
||||
assertThat(c3.closed, is(false)); |
||||
assertThat(c4.closed, is(false)); |
||||
assertThat(c5.closed, is(false)); |
||||
assertThat(c6.closed, is(false)); |
||||
ctx.close(); |
||||
assertThat("c0", c0.closed, is(true)); |
||||
assertThat("c1", c1.closed, is(true)); |
||||
assertThat("c2", c2.closed, is(true)); |
||||
assertThat("c3", c3.closed, is(true)); |
||||
assertThat("c4", c4.closed, is(true)); |
||||
assertThat("c5", c5.closed, is(true)); |
||||
assertThat("c6", c6.closed, is(false)); |
||||
} |
||||
|
||||
@Test |
||||
public void xml() { |
||||
ConfigurableApplicationContext ctx = new GenericXmlApplicationContext( |
||||
getClass(), "DestroyMethodInferenceTests-context.xml"); |
||||
WithLocalCloseMethod x1 = ctx.getBean("x1", WithLocalCloseMethod.class); |
||||
WithLocalCloseMethod x2 = ctx.getBean("x2", WithLocalCloseMethod.class); |
||||
WithLocalCloseMethod x3 = ctx.getBean("x3", WithLocalCloseMethod.class); |
||||
WithNoCloseMethod x4 = ctx.getBean("x4", WithNoCloseMethod.class); |
||||
assertThat(x1.closed, is(false)); |
||||
assertThat(x2.closed, is(false)); |
||||
assertThat(x3.closed, is(false)); |
||||
assertThat(x4.closed, is(false)); |
||||
ctx.close(); |
||||
assertThat(x1.closed, is(false)); |
||||
assertThat(x2.closed, is(true)); |
||||
assertThat(x3.closed, is(true)); |
||||
assertThat(x4.closed, is(false)); |
||||
} |
||||
|
||||
@Configuration |
||||
static class Config { |
||||
@Bean(destroyMethod="explicitClose") |
||||
public WithExplicitDestroyMethod c0() { |
||||
return new WithExplicitDestroyMethod(); |
||||
} |
||||
|
||||
@Bean |
||||
public WithLocalCloseMethod c1() { |
||||
return new WithLocalCloseMethod(); |
||||
} |
||||
|
||||
@Bean |
||||
public Object c2() { |
||||
return new WithLocalCloseMethod(); |
||||
} |
||||
|
||||
@Bean |
||||
public WithInheritedCloseMethod c3() { |
||||
return new WithInheritedCloseMethod(); |
||||
} |
||||
|
||||
@Bean |
||||
public Closeable c4() { |
||||
return new WithInheritedCloseMethod(); |
||||
} |
||||
|
||||
@Bean(destroyMethod="other") |
||||
public WithInheritedCloseMethod c5() { |
||||
return new WithInheritedCloseMethod() { |
||||
@Override |
||||
public void close() throws IOException { |
||||
throw new RuntimeException("close() should not be called"); |
||||
} |
||||
@SuppressWarnings("unused") |
||||
public void other() { |
||||
this.closed = true; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
@Bean |
||||
public WithNoCloseMethod c6() { |
||||
return new WithNoCloseMethod(); |
||||
} |
||||
} |
||||
|
||||
|
||||
static class WithExplicitDestroyMethod { |
||||
boolean closed = false; |
||||
public void explicitClose() { |
||||
closed = true; |
||||
} |
||||
} |
||||
|
||||
static class WithLocalCloseMethod { |
||||
boolean closed = false; |
||||
public void close() { |
||||
closed = true; |
||||
} |
||||
} |
||||
|
||||
static class WithInheritedCloseMethod implements Closeable { |
||||
boolean closed = false; |
||||
public void close() throws IOException { |
||||
closed = true; |
||||
} |
||||
} |
||||
|
||||
static class WithNoCloseMethod { |
||||
boolean closed = false; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue