Skip to content

Commit 6ad647d

Browse files
committed
Explicit hints for @PostConstruct methods (preventing deadlocks)
Closes gh-25074
1 parent 384246c commit 6ad647d

File tree

1 file changed

+57
-21
lines changed

1 file changed

+57
-21
lines changed

framework-docs/modules/ROOT/pages/core/beans/factory-nature.adoc

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ startup and shutdown process, as driven by the container's own lifecycle.
4242
The lifecycle callback interfaces are described in this section.
4343

4444

45+
4546
[[beans-factory-lifecycle-initializingbean]]
4647
=== Initialization Callbacks
4748

@@ -132,6 +133,30 @@ Kotlin::
132133

133134
However, the first of the two preceding examples does not couple the code to Spring.
134135

136+
[NOTE]
137+
====
138+
Be aware that `@PostConstruct` and initialization methods in general are executed
139+
within the container's singleton creation lock. The bean instance is only considered
140+
as fully initialized and ready to be published to others after returning from the
141+
`@PostConstruct` method. Such individual initialization methods are only meant
142+
for validating the configuration state and possibly preparing some data structures
143+
based on the given configuration but no further activity with external bean access.
144+
Otherwise there is a risk for an initialization deadlock.
145+
146+
For a scenario where expensive post-initialization activity is to be triggered,
147+
e.g. asynchronous database preparation steps, your bean should either implement
148+
`SmartInitializingSingleton.afterSingletonsInstantiated()` or rely on the context
149+
refresh event: implementing `ApplicationListener<ContextRefreshedEvent>` or
150+
declaring its annotation equivalent `@EventListener(ContextRefreshedEvent.class)`.
151+
Those variants come after all regular singleton initialization and therefore
152+
outside of any singleton creation lock.
153+
154+
Alternatively, you may implement the `(Smart)Lifecycle` interface and integrate with
155+
the container's overall lifecycle management, including an auto-startup mechanism,
156+
a pre-destroy stop step, and potential stop/restart callbacks (see below).
157+
====
158+
159+
135160

136161
[[beans-factory-lifecycle-disposablebean]]
137162
=== Destruction Callbacks
@@ -223,31 +248,41 @@ Kotlin::
223248
However, the first of the two preceding definitions does not couple the code to Spring.
224249

225250
TIP: You can assign the `destroy-method` attribute of a `<bean>` element a special
226-
`(inferred)` value, which instructs Spring to automatically detect a public `close` or
227-
`shutdown` method on the specific bean class. (Any class that implements
228-
`java.lang.AutoCloseable` or `java.io.Closeable` would therefore match.) You can also set
229-
this special `(inferred)` value on the `default-destroy-method` attribute of a
251+
`(inferred)` value, which instructs Spring to automatically detect a public `close`
252+
or `shutdown` method on the specific bean class. (Any class that implements
253+
`java.lang.AutoCloseable` or `java.io.Closeable` would therefore match.) You can also
254+
set this special `(inferred)` value on the `default-destroy-method` attribute of a
230255
`<beans>` element to apply this behavior to an entire set of beans (see
231-
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-default-init-destroy-methods[Default Initialization and Destroy Methods]). Note that this is the
232-
default behavior with Java configuration.
256+
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-default-init-destroy-methods[Default Initialization and Destroy Methods]).
257+
Note that this is the default behavior for `@Bean` methods in Java configuration classes.
258+
259+
[NOTE]
260+
====
261+
For extended shutdown phases, you may implement the `Lifecycle` interface and receive
262+
an early stop signal before the destroy methods of any singleton beans are called.
263+
You may also implement `SmartLifecycle` for a time-bound stop step where the container
264+
will wait for all such stop processing to complete before moving on to destroy methods.
265+
====
266+
267+
233268

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

237272
When you write initialization and destroy method callbacks that do not use the
238273
Spring-specific `InitializingBean` and `DisposableBean` callback interfaces, you
239-
typically write methods with names such as `init()`, `initialize()`, `dispose()`, and so
240-
on. Ideally, the names of such lifecycle callback methods are standardized across a
241-
project so that all developers use the same method names and ensure consistency.
274+
typically write methods with names such as `init()`, `initialize()`, `dispose()`,
275+
and so on. Ideally, the names of such lifecycle callback methods are standardized across
276+
a project so that all developers use the same method names and ensure consistency.
242277

243278
You can configure the Spring container to "`look`" for named initialization and destroy
244-
callback method names on every bean. This means that you, as an application
245-
developer, can write your application classes and use an initialization callback called
246-
`init()`, without having to configure an `init-method="init"` attribute with each bean
247-
definition. The Spring IoC container calls that method when the bean is created (and in
248-
accordance with the standard lifecycle callback contract xref:core/beans/factory-nature.adoc#beans-factory-lifecycle[described previously]
249-
). This feature also enforces a consistent naming convention for
250-
initialization and destroy method callbacks.
279+
callback method names on every bean. This means that you, as an application developer,
280+
can write your application classes and use an initialization callback called `init()`,
281+
without having to configure an `init-method="init"` attribute with each bean definition.
282+
The Spring IoC container calls that method when the bean is created (and in accordance
283+
with the standard lifecycle callback contract xref:core/beans/factory-nature.adoc#beans-factory-lifecycle[described previously]).
284+
This feature also enforces a consistent naming convention for initialization and
285+
destroy method callbacks.
251286

252287
Suppose that your initialization callback methods are named `init()` and your destroy
253288
callback methods are named `destroy()`. Your class then resembles the class in the
@@ -407,14 +442,15 @@ and closed.
407442
[TIP]
408443
====
409444
Note that the regular `org.springframework.context.Lifecycle` interface is a plain
410-
contract for explicit start and stop notifications and does not imply auto-startup at context
411-
refresh time. For fine-grained control over auto-startup of a specific bean (including startup phases),
412-
consider implementing `org.springframework.context.SmartLifecycle` instead.
445+
contract for explicit start and stop notifications and does not imply auto-startup
446+
at context refresh time. For fine-grained control over auto-startup and for graceful
447+
stopping of a specific bean (including startup and stop phases), consider implementing
448+
the extended `org.springframework.context.SmartLifecycle` interface instead.
413449
414450
Also, please note that stop notifications are not guaranteed to come before destruction.
415451
On regular shutdown, all `Lifecycle` beans first receive a stop notification before
416-
the general destruction callbacks are being propagated. However, on hot refresh during a
417-
context's lifetime or on stopped refresh attempts, only destroy methods are called.
452+
the general destruction callbacks are being propagated. However, on hot refresh during
453+
a context's lifetime or on stopped refresh attempts, only destroy methods are called.
418454
====
419455

420456
The order of startup and shutdown invocations can be important. If a "`depends-on`"

0 commit comments

Comments
 (0)