Card 04/ 07

ConceptDifficulty: Intermediate1 min

@PostConstruct and @PreDestroy: Lifecycle Callbacks and Prototype Beans

The container calls a singleton's clean-up method on shutdown, and never calls a prototype's.

@PostConstruct marks a method the container calls once, right after a bean's dependencies are set, and @PreDestroy marks one it calls on shutdown, just before the bean is discarded. These lifecycle callbacks are where a bean opens and releases resources, such as a connection or a file.

A receipt printer holds a connection that must be closed on shutdown. As a singleton, the one shared instance the container keeps for its whole life, closing the context runs its @PreDestroy method and the connection is released. As a prototype, a bean the container creates afresh each time it is asked for, the same method is never called.

Both callbacks work as expected for a singleton. For a prototype only half of the promise holds: the container creates it, runs @PostConstruct, hands it over, and then stops tracking it. It cannot know when you are finished with a prototype, so it never calls @PreDestroy on one.

@PostConstruct is not the same as the constructor. When the constructor runs, dependencies injected into fields are not set yet, so work that needs them belongs in the @PostConstruct method. With constructor injection the constructor already has everything, which is why many beans need no @PostConstruct at all. Both annotations come from the jakarta.annotation package.

text
closing context...
singleton receipt cleaned up
closed.
a singleton's @PreDestroy runs on context.close(); a prototype's, registered the same way, never prints

So once a prototype bean is handed over, cleaning it up is the caller's job, exactly as for any object you created with new. A prototype that holds a resource needs a caller that remembers to release it.