Skip to content

Commit

Permalink
Leniently tolerate late bean retrieval during destroySingletons()
Browse files Browse the repository at this point in the history
Closes gh-22526
Closes gh-29730
  • Loading branch information
jhoeller committed Mar 4, 2024
1 parent 138e7a0 commit b5ca646
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
@Nullable
private volatile Thread singletonCreationThread;

/** Flag that indicates whether we're currently within destroySingletons. */
private volatile boolean singletonsCurrentlyInDestruction = false;

/** Collection of suppressed Exceptions, available for associating related causes. */
@Nullable
private Set<Exception> suppressedExceptions;

/** Flag that indicates whether we're currently within destroySingletons. */
private boolean singletonsCurrentlyInDestruction = false;

/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();

Expand Down Expand Up @@ -562,13 +562,7 @@ public void destroySingletons() {
if (logger.isTraceEnabled()) {
logger.trace("Destroying singletons in " + this);
}
this.singletonLock.lock();
try {
this.singletonsCurrentlyInDestruction = true;
}
finally {
this.singletonLock.unlock();
}
this.singletonsCurrentlyInDestruction = true;

String[] disposableBeanNames;
synchronized (this.disposableBeans) {
Expand Down Expand Up @@ -610,21 +604,28 @@ protected void clearSingletonCache() {
* @see #destroyBean
*/
public void destroySingleton(String beanName) {
// Remove a registered singleton of the given name, if any.
this.singletonLock.lock();
try {
removeSingleton(beanName);
}
finally {
this.singletonLock.unlock();
}

// Destroy the corresponding DisposableBean instance.
// This also triggers the destruction of dependent beans.
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
disposableBean = this.disposableBeans.remove(beanName);
}
destroyBean(beanName, disposableBean);

// destroySingletons() removes all singleton instances at the end,
// leniently tolerating late retrieval during the shutdown phase.
if (!this.singletonsCurrentlyInDestruction) {
// For an individual destruction, remove the registered instance now.
// As of 6.2, this happens after the current bean's destruction step,
// allowing for late bean retrieval by on-demand suppliers etc.
this.singletonLock.lock();
try {
removeSingleton(beanName);
}
finally {
this.singletonLock.unlock();
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,11 @@ public void destroy() {
Assert.state(applicationContext.getBean("messageSource") instanceof StaticMessageSource,
"Invalid MessageSource bean");
try {
// Should not throw BeanCreationNotAllowedException on 6.2 anymore
applicationContext.getBean("service2");
// Should have thrown BeanCreationNotAllowedException
properlyDestroyed = false;
}
catch (BeanCreationNotAllowedException ex) {
// expected
properlyDestroyed = false;
}
});
thread.start();
Expand Down

0 comments on commit b5ca646

Please sign in to comment.