Skip to content

Commit

Permalink
Improve documentation on inferred destruction callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
Nheyll committed Jul 4, 2023
1 parent 35667e8 commit a73e3c5
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 58 deletions.
2 changes: 1 addition & 1 deletion framework-docs/antora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ nav:
ext:
collector:
run:
command: gradlew -q -PbuildSrc.skipTests=true "-Dorg.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError" :framework-docs:generateAntoraResources
command: gradlew -q -PbuildSrc.skipTests=true "-Dorg.gradle.jvmargs=-Xmx3g :framework-docs:generateAntoraResources
local: true
scan:
dir: ./build/generated-antora-resources
Expand Down
74 changes: 64 additions & 10 deletions framework-docs/modules/ROOT/pages/core/beans/factory-nature.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,69 @@ However, the first of the two preceding examples does not couple the code to Spr
[[beans-factory-lifecycle-disposablebean]]
=== Destruction Callbacks

Destruction callbacks can be inferred using a `close` or `shutdown` method, or explicit using
`DisposableBean` interface, xref:core/beans/annotation-config/postconstruct-and-predestroy-annotations.adoc[`@PreDestroy`]
annotation or `destroy-method` attribute.

[[beans-factory-lifecycle-destruction-callback-inferred]]
==== Inferred destruction methods

By default, beans defined with Java configuration that have a public `close` or `shutdown`
method are automatically enlisted with a destruction callback. If you have a public
`close` or `shutdown` method and you do not wish for it to be called when the container
shuts down, you can add `@Bean(destroyMethod = "")` to your bean definition to disable the
default `(inferred)` mode.

[NOTE]
=====
You may want to disable the default `(inferred)` mode for a resource that you acquire with JNDI, as its
lifecycle is managed outside the application. In particular, make sure to always do it
for a `DataSource`, as it is known to be problematic on Jakarta EE application servers.
The following example shows how to prevent an automatic destruction callback for a
`DataSource`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@Bean(destroyMethod = "")
public DataSource dataSource() throws NamingException {
return (DataSource) jndiTemplate.lookup("MyDS");
}
----

Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@Bean(destroyMethod = "")
fun dataSource(): DataSource {
return jndiTemplate.lookup("MyDS") as DataSource
}
----
======
Also, with `@Bean` methods, you typically use programmatic JNDI lookups, either by
using Spring's `JndiTemplate` or `JndiLocatorDelegate` helpers or straight JNDI
`InitialContext` usage but not the `JndiObjectFactoryBean` variant (which would force
you to declare the return type as the `FactoryBean` type instead of the actual target
type, making it harder to use for cross-reference calls in other `@Bean` methods that
intend to refer to the provided resource here).
=====

In XML Spring configuration, you can assign the `destroy-method` attribute of a `<bean>` element the special
`(inferred)` value, which instructs Spring to automatically detect a public `close` or
`shutdown` method on the specific bean class. (Any class that implements
`java.lang.AutoCloseable` or `java.io.Closeable` would therefore match.) You can also set
this special `(inferred)` value on the `default-destroy-method` attribute of a
`<beans>` element to apply this behavior to an entire set of beans (see
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-default-init-destroy-methods[Default Initialization and Destroy Methods]).

[[beans-factory-lifecycle-destruction-callback-explicit]]
==== Explicit destruction methods
Implementing the `org.springframework.beans.factory.DisposableBean` interface lets a
bean get a callback when the container that contains it is destroyed. The
`DisposableBean` interface specifies a single method:
Expand Down Expand Up @@ -222,15 +285,6 @@ Kotlin::

However, the first of the two preceding definitions does not couple the code to Spring.

TIP: You can assign the `destroy-method` attribute of a `<bean>` element a special
`(inferred)` value, which instructs Spring to automatically detect a public `close` or
`shutdown` method on the specific bean class. (Any class that implements
`java.lang.AutoCloseable` or `java.io.Closeable` would therefore match.) You can also set
this special `(inferred)` value on the `default-destroy-method` attribute of a
`<beans>` element to apply this behavior to an entire set of beans (see
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-default-init-destroy-methods[Default Initialization and Destroy Methods]). Note that this is the
default behavior with Java configuration.

[[beans-factory-lifecycle-default-init-destroy-methods]]
=== Default Initialization and Destroy Methods

Expand Down Expand Up @@ -339,7 +393,7 @@ interacts directly with the raw target bean.
As of Spring 2.5, you have three options for controlling bean lifecycle behavior:

* The xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-initializingbean[`InitializingBean`] and
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-disposablebean[`DisposableBean`] callback interfaces
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-destruction-callback-explicit[`DisposableBean`] callback interfaces
* Custom `init()` and `destroy()` methods
* The xref:core/beans/annotation-config/postconstruct-and-predestroy-annotations.adoc[`@PostConstruct` and `@PreDestroy` annotations]
. You can combine these mechanisms to control a given bean.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
The annotation supports some of the attributes offered by `<bean/>`, such as:

* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-initializingbean[init-method]
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-disposablebean[destroy-method]
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-destruction-callback-explicit[destroy-method]
* xref:core/beans/dependencies/factory-autowire.adoc[autowiring]
* `name`.

Expand Down Expand Up @@ -193,6 +193,11 @@ and can use the `@PostConstruct` and `@PreDestroy` annotations from JSR-250. See
xref:core/beans/annotation-config/postconstruct-and-predestroy-annotations.adoc[JSR-250 annotations] for further
details.

Any classes defined with the `@Bean` annotation also support inferred destruction methods and detect
any public `close` or `shutdown` method as a destruction callback. See
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-destruction-callback-inferred[Inferred destruction methods]
for further details.

The regular Spring xref:core/beans/factory-nature.adoc[lifecycle] callbacks are fully supported as
well. If a bean implements `InitializingBean`, `DisposableBean`, or `Lifecycle`, their
respective methods are called by the container.
Expand Down Expand Up @@ -271,52 +276,6 @@ class AppConfig {
----
======

[NOTE]
=====
By default, beans defined with Java configuration that have a public `close` or `shutdown`
method are automatically enlisted with a destruction callback. If you have a public
`close` or `shutdown` method and you do not wish for it to be called when the container
shuts down, you can add `@Bean(destroyMethod = "")` to your bean definition to disable the
default `(inferred)` mode.
You may want to do that by default for a resource that you acquire with JNDI, as its
lifecycle is managed outside the application. In particular, make sure to always do it
for a `DataSource`, as it is known to be problematic on Jakarta EE application servers.
The following example shows how to prevent an automatic destruction callback for a
`DataSource`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@Bean(destroyMethod = "")
public DataSource dataSource() throws NamingException {
return (DataSource) jndiTemplate.lookup("MyDS");
}
----

Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@Bean(destroyMethod = "")
fun dataSource(): DataSource {
return jndiTemplate.lookup("MyDS") as DataSource
}
----
======
Also, with `@Bean` methods, you typically use programmatic JNDI lookups, either by
using Spring's `JndiTemplate` or `JndiLocatorDelegate` helpers or straight JNDI
`InitialContext` usage but not the `JndiObjectFactoryBean` variant (which would force
you to declare the return type as the `FactoryBean` type instead of the actual target
type, making it harder to use for cross-reference calls in other `@Bean` methods that
intend to refer to the provided resource here).
=====

In the case of `BeanOne` from the example above the preceding note, it would be equally valid to call the `init()`
method directly during construction, as the following example shows:

Expand Down

0 comments on commit a73e3c5

Please sign in to comment.