Skip to content

Commit

Permalink
Revise singleton registry for lenient locking (fallback instead of de…
Browse files Browse the repository at this point in the history
…adlock)

Closes gh-23501
  • Loading branch information
jhoeller committed Feb 19, 2024
1 parent f529386 commit 902e570
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 195 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -109,13 +109,8 @@ public Object getAspectCreationMutex() {
// Rely on singleton semantics provided by the factory -> no local lock.
return null;
}
else if (this.beanFactory instanceof ConfigurableBeanFactory cbf) {
// No singleton guarantees from the factory -> let's lock locally but
// reuse the factory's singleton lock, just in case a lazy dependency
// of our advice bean happens to trigger the singleton lock implicitly...
return cbf.getSingletonMutex();
}
else {
// No singleton guarantees from the factory -> let's lock locally.
return this;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,7 +23,6 @@

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

Expand Down Expand Up @@ -52,7 +51,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
@Nullable
private transient volatile Advice advice;

private transient volatile Object adviceMonitor = new Object();
private transient Object adviceMonitor = new Object();


/**
Expand All @@ -78,16 +77,6 @@ public String getAdviceBeanName() {
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
resetAdviceMonitor();
}

private void resetAdviceMonitor() {
if (this.beanFactory instanceof ConfigurableBeanFactory cbf) {
this.adviceMonitor = cbf.getSingletonMutex();
}
else {
this.adviceMonitor = new Object();
}
}

/**
Expand Down Expand Up @@ -118,9 +107,7 @@ public Advice getAdvice() {
return advice;
}
else {
// No singleton guarantees from the factory -> let's lock locally but
// reuse the factory's singleton lock, just in case a lazy dependency
// of our advice bean happens to trigger the singleton lock implicitly...
// No singleton guarantees from the factory -> let's lock locally.
synchronized (this.adviceMonitor) {
advice = this.advice;
if (advice == null) {
Expand Down Expand Up @@ -155,7 +142,7 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
ois.defaultReadObject();

// Initialize transient fields.
resetAdviceMonitor();
this.adviceMonitor = new Object();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -129,7 +129,10 @@ public interface SingletonBeanRegistry {
* Return the singleton mutex used by this registry (for external collaborators).
* @return the mutex object (never {@code null})
* @since 4.2
* @deprecated as of 6.2, in favor of lenient singleton locking
* (with this method returning an arbitrary object to lock on)
*/
@Deprecated(since = "6.2")
Object getSingletonMutex();

}
Original file line number Diff line number Diff line change
Expand Up @@ -972,59 +972,54 @@ protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd,
*/
@Nullable
private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
synchronized (getSingletonMutex()) {
BeanWrapper bw = this.factoryBeanInstanceCache.get(beanName);
if (bw != null) {
return (FactoryBean<?>) bw.getWrappedInstance();
}
Object beanInstance = getSingleton(beanName, false);
if (beanInstance instanceof FactoryBean<?> factoryBean) {
return factoryBean;
}
if (isSingletonCurrentlyInCreation(beanName) ||
(mbd.getFactoryBeanName() != null && isSingletonCurrentlyInCreation(mbd.getFactoryBeanName()))) {
return null;
}
BeanWrapper bw = this.factoryBeanInstanceCache.get(beanName);
if (bw != null) {
return (FactoryBean<?>) bw.getWrappedInstance();
}
Object beanInstance = getSingleton(beanName, false);
if (beanInstance instanceof FactoryBean<?> factoryBean) {
return factoryBean;
}
if (isSingletonCurrentlyInCreation(beanName) ||
(mbd.getFactoryBeanName() != null && isSingletonCurrentlyInCreation(mbd.getFactoryBeanName()))) {
return null;
}

Object instance;
try {
// Mark this bean as currently in creation, even if just partially.
beforeSingletonCreation(beanName);
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
instance = resolveBeforeInstantiation(beanName, mbd);
if (instance == null) {
bw = createBeanInstance(beanName, mbd, null);
instance = bw.getWrappedInstance();
}
Object instance;
try {
// Mark this bean as currently in creation, even if just partially.
beforeSingletonCreation(beanName);
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
instance = resolveBeforeInstantiation(beanName, mbd);
if (instance == null) {
bw = createBeanInstance(beanName, mbd, null);
instance = bw.getWrappedInstance();
this.factoryBeanInstanceCache.put(beanName, bw);
}
catch (UnsatisfiedDependencyException ex) {
// Don't swallow, probably misconfiguration...
}
catch (UnsatisfiedDependencyException ex) {
// Don't swallow, probably misconfiguration...
throw ex;
}
catch (BeanCreationException ex) {
// Don't swallow a linkage error since it contains a full stacktrace on
// first occurrence... and just a plain NoClassDefFoundError afterwards.
if (ex.contains(LinkageError.class)) {
throw ex;
}
catch (BeanCreationException ex) {
// Don't swallow a linkage error since it contains a full stacktrace on
// first occurrence... and just a plain NoClassDefFoundError afterwards.
if (ex.contains(LinkageError.class)) {
throw ex;
}
// Instantiation failure, maybe too early...
if (logger.isDebugEnabled()) {
logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex);
}
onSuppressedException(ex);
return null;
}
finally {
// Finished partial creation of this bean.
afterSingletonCreation(beanName);
}

FactoryBean<?> fb = getFactoryBean(beanName, instance);
if (bw != null) {
this.factoryBeanInstanceCache.put(beanName, bw);
// Instantiation failure, maybe too early...
if (logger.isDebugEnabled()) {
logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex);
}
return fb;
onSuppressedException(ex);
return null;
}
finally {
// Finished partial creation of this bean.
afterSingletonCreation(beanName);
}

return getFactoryBean(beanName, instance);
}

/**
Expand Down Expand Up @@ -1912,21 +1907,17 @@ protected Object postProcessObjectFromFactoryBean(Object object, String beanName
*/
@Override
protected void removeSingleton(String beanName) {
synchronized (getSingletonMutex()) {
super.removeSingleton(beanName);
this.factoryBeanInstanceCache.remove(beanName);
}
super.removeSingleton(beanName);
this.factoryBeanInstanceCache.remove(beanName);
}

/**
* Overridden to clear FactoryBean instance cache as well.
*/
@Override
protected void clearSingletonCache() {
synchronized (getSingletonMutex()) {
super.clearSingletonCache();
this.factoryBeanInstanceCache.clear();
}
super.clearSingletonCache();
this.factoryBeanInstanceCache.clear();
}

/**
Expand Down

0 comments on commit 902e570

Please sign in to comment.