Description
Archie Cobbs opened SPR-9391 and commented
Spring has some very counter-intuitive behavior when handling prototype scoped and @Configurable
beans, or more generally, beans whose lifecycles are "smaller" than the lifecycle of the overall application context (e.g., that of singleton beans).
The issue is that initialization activity occurs for these beans (e.g., InitializingBean
) but destruction activity does not (e.g., DisposableBean
). For just one example, #11326 complains about this.
Related to this is the non-intuitive behavior that ApplicationListener
doesn't work at all for prototype and @Configurable
beans, presumably because there's no way for the application context to know when to unregister the listener (e.g., see the code quoted in #14023).
This contributes to much confusion about Spring. But even worse, the typical result for unaware programmers is memory leaks. This is due to destruction activity that never occurs, such as listeners that don't get unregistered, etc. In a servlet container environment, this can then cause class loader leaks on web application restart, etc.
All of these problems can be solved easily: have the application context maintain weak references to these beans, along with a corresponding reference queue, and invoke all of the destruction callbacks whenever any bean appears on the reference queue. In addition, when the application context itself is shutdown, since there can still be "live" prototype and @Configurable
beans, we need to find and destruct them; but these beans will exist as uncleared weak references, which can then be iteratively destructed (presumably we are discarding the weak references after destructing the corresponding bean, so at any given time the weak references we maintain represent only the "live" beans).
To avoid having to create a new thread to poll the reference queue, the application context can poll the reference queue every time a new prototype or @Configurable
bean is instantiated, etc. This ensures that there can be no memory leak caused by the maintenance of the references themselves. Regarding the behavior of destructor timing, in the worst case, beans will be always be destructed on application context shutdown, but typically much sooner. Better late than never!
FYI, this idea was originally mentioned in #9922; I'm just elaborating on it.
Affects: 3.1.1
Issue Links:
- Introduce removeApplicationListener in ConfigurableApplicationContext #14023 Add new method ConfigurableApplicationContext.removeApplicationListener()
- Disallow destroy-method when scope is prototype [SPR-6660] #11326 Disallow destroy-method when scope is prototype
- Prototype application context event listeners are not notified within the events [SPR-5248] #9922 Prototype application context event listeners are not notified within the events
2 votes, 4 watchers