在Spring中对单列对象存储都会使用到三级缓存,三级缓存存在的目的主要是解决循环依赖问题。只有单例才会使用到缓存,其他对象创建不会放入到缓存中
一、类继承关系

二、核心类和对象
1.
Spring 三级缓存模块中核心的类:defaultSingletonBeanRegistry 三级缓存对象:
- singletonObjects :一级缓存,主要存储创建后完整的bean对象
- singletonFactories: 三级缓存,主要存储创建后的beanFactroy对象,并存储真正的bean对象
- earlySingletonObjects: 二级缓存,存储bean对象
- registeredSingletons: 已经完成注册的对象
核心方法:
- registerSingleton(): 注册单例对象
- addSingleton(): 添加单例对象到一级缓存中
- 添加对象进入到一级缓存
- 删除二、三级缓存对象
- 添加bean 对象 Set 集合
- getSingleton(): 通过beanName 获取 bean对象
�
基本对象属性 ```java public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/ Cache of singleton objects: bean name —> bean instance */ / 一级缓存 **/ private final Map
singletonObjects = new ConcurrentHashMap<>(256); / Cache of singleton factories: bean name —> ObjectFactory */ / 三级缓存 **/ private final Map
> singletonFactories = new HashMap<>(16); / Cache of early singleton objects: bean name —> bean instance */ / 二级缓存 **/ private final Map
earlySingletonObjects = new HashMap<>(16); /* Set of registered singletons, containing the bean names in registration order / // 所有单列对象集合,并按照beanName 进行排序 private final Set
registeredSingletons = new LinkedHashSet<>(256); /* Names of beans that are currently in creation / private final Set
singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/* Names of beans currently excluded from in creation checks / private final Set
inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/* List of suppressed Exceptions, available for associating related causes / @Nullable private Set
suppressedExceptions; /* Flag that indicates whether we’re currently within destroySingletons / private boolean singletonsCurrentlyInDestruction = false;
/* Disposable bean instances: bean name —> disposable instance / private final Map
disposableBeans = new LinkedHashMap<>(); /* Map between containing bean names: bean name —> Set of bean names that the bean contains / private final Map
> containedBeanMap = new ConcurrentHashMap<>(16); /* Map between dependent bean names: bean name —> Set of dependent bean names / private final Map
> dependentBeanMap = new ConcurrentHashMap<>(64); /* Map between depending bean names: bean name —> Set of bean names for the bean’s dependencies / private final Map
> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
}
3. 基本方法1. 注册单列对象```java/*** 注册单列对象* @param beanName the name of the bean* @param singletonObject the existing singleton object* @throws IllegalStateException*/@Overridepublic void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {Assert.notNull(beanName, "Bean name must not be null");Assert.notNull(singletonObject, "Singleton object must not be null");synchronized (this.singletonObjects) {Object oldObject = this.singletonObjects.get(beanName);if (oldObject != null) {throw new IllegalStateException("Could not register object [" + singletonObject +"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");}addSingleton(beanName, singletonObject);}}/*** Add the given singleton object to the singleton cache of this factory.* <p>To be called for eager registration of singletons.* @param beanName the name of the bean* @param singletonObject the singleton object*/protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}/*** Add the given singleton factory for building the specified singleton* if necessary.* <p>To be called for eager registration of singletons, e.g. to be able to* resolve circular references.* @param beanName the name of the bean* @param singletonFactory the factory for the singleton object*/protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}
获取对象 ```java @Override @Nullable public Object getSingleton(String beanName) { return getSingleton(beanName, true); }
/**
- Return the (raw) singleton object registered under the given name.
Checks already instantiated singletons and also allows for an early
- reference to a currently created singleton (resolving a circular reference).
- @param beanName the name of the bean to look for
- @param allowEarlyReference whether early references should be created or not
- @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
} return singletonObject; }synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}
/**
- Return the (raw) singleton object registered under the given name,
- creating and registering a new one if none registered yet.
- @param beanName the name of the bean
- @param singletonFactory the ObjectFactory to lazily create the singleton
- with, if necessary
- @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, “Bean name must not be null”);
synchronized (this.singletonObjects) {
} }Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}afterSingletonCreation(beanName);}if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;
3. a3. <br />3. <br />4. 全部代码```javapublic class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {/** Cache of singleton objects: bean name --> bean instance *//** 一级缓存 **/private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name --> ObjectFactory *//** 三级缓存 **/private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name --> bean instance *//** 二级缓存 **/private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);/** Set of registered singletons, containing the bean names in registration order */// 所有单列对象集合,并按照beanName 进行排序private final Set<String> registeredSingletons = new LinkedHashSet<>(256);/** Names of beans that are currently in creation */private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));/** Names of beans currently excluded from in creation checks */private final Set<String> inCreationCheckExclusions =Collections.newSetFromMap(new ConcurrentHashMap<>(16));/** List of suppressed Exceptions, available for associating related causes */@Nullableprivate Set<Exception> suppressedExceptions;/** Flag that indicates whether we're currently within destroySingletons */private boolean singletonsCurrentlyInDestruction = false;/** Disposable bean instances: bean name --> disposable instance */private final Map<String, Object> disposableBeans = new LinkedHashMap<>();/** Map between containing bean names: bean name --> Set of bean names that the bean contains */private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);/** Map between dependent bean names: bean name --> Set of dependent bean names */private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);/** Map between depending bean names: bean name --> Set of bean names for the bean's dependencies */private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);@Overridepublic void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {Assert.notNull(beanName, "Bean name must not be null");Assert.notNull(singletonObject, "Singleton object must not be null");synchronized (this.singletonObjects) {Object oldObject = this.singletonObjects.get(beanName);if (oldObject != null) {throw new IllegalStateException("Could not register object [" + singletonObject +"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");}addSingleton(beanName, singletonObject);}}/*** Add the given singleton object to the singleton cache of this factory.* <p>To be called for eager registration of singletons.* @param beanName the name of the bean* @param singletonObject the singleton object*/protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}/*** Add the given singleton factory for building the specified singleton* if necessary.* <p>To be called for eager registration of singletons, e.g. to be able to* resolve circular references.* @param beanName the name of the bean* @param singletonFactory the factory for the singleton object*/protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}@Override@Nullablepublic Object getSingleton(String beanName) {return getSingleton(beanName, true);}/*** Return the (raw) singleton object registered under the given name.* <p>Checks already instantiated singletons and also allows for an early* reference to a currently created singleton (resolving a circular reference).* @param beanName the name of the bean to look for* @param allowEarlyReference whether early references should be created or not* @return the registered singleton object, or {@code null} if none found*/@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}/*** Return the (raw) singleton object registered under the given name,* creating and registering a new one if none registered yet.* @param beanName the name of the bean* @param singletonFactory the ObjectFactory to lazily create the singleton* with, if necessary* @return the registered singleton object*/public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}afterSingletonCreation(beanName);}if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}}/*** Register an Exception that happened to get suppressed during the creation of a* singleton bean instance, e.g. a temporary circular reference resolution problem.* @param ex the Exception to register*/protected void onSuppressedException(Exception ex) {synchronized (this.singletonObjects) {if (this.suppressedExceptions != null) {this.suppressedExceptions.add(ex);}}}/*** Remove the bean with the given name from the singleton cache of this factory,* to be able to clean up eager registration of a singleton if creation failed.* @param beanName the name of the bean* @see #getSingletonMutex()*/protected void removeSingleton(String beanName) {synchronized (this.singletonObjects) {this.singletonObjects.remove(beanName);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.remove(beanName);}}@Overridepublic boolean containsSingleton(String beanName) {return this.singletonObjects.containsKey(beanName);}@Overridepublic String[] getSingletonNames() {synchronized (this.singletonObjects) {return StringUtils.toStringArray(this.registeredSingletons);}}@Overridepublic int getSingletonCount() {synchronized (this.singletonObjects) {return this.registeredSingletons.size();}}public void setCurrentlyInCreation(String beanName, boolean inCreation) {Assert.notNull(beanName, "Bean name must not be null");if (!inCreation) {this.inCreationCheckExclusions.add(beanName);}else {this.inCreationCheckExclusions.remove(beanName);}}public boolean isCurrentlyInCreation(String beanName) {Assert.notNull(beanName, "Bean name must not be null");return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName));}protected boolean isActuallyInCreation(String beanName) {return isSingletonCurrentlyInCreation(beanName);}/*** Return whether the specified singleton bean is currently in creation* (within the entire factory).* @param beanName the name of the bean*/public boolean isSingletonCurrentlyInCreation(String beanName) {return this.singletonsCurrentlyInCreation.contains(beanName);}/*** Callback before singleton creation.* <p>The default implementation register the singleton as currently in creation.* @param beanName the name of the singleton about to be created* @see #isSingletonCurrentlyInCreation*/protected void beforeSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}}/*** Callback after singleton creation.* <p>The default implementation marks the singleton as not in creation anymore.* @param beanName the name of the singleton that has been created* @see #isSingletonCurrentlyInCreation*/protected void afterSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");}}/*** Add the given bean to the list of disposable beans in this registry.* <p>Disposable beans usually correspond to registered singletons,* matching the bean name but potentially being a different instance* (for example, a DisposableBean adapter for a singleton that does not* naturally implement Spring's DisposableBean interface).* @param beanName the name of the bean* @param bean the bean instance*/public void registerDisposableBean(String beanName, DisposableBean bean) {synchronized (this.disposableBeans) {this.disposableBeans.put(beanName, bean);}}/*** Register a containment relationship between two beans,* e.g. between an inner bean and its containing outer bean.* <p>Also registers the containing bean as dependent on the contained bean* in terms of destruction order.* @param containedBeanName the name of the contained (inner) bean* @param containingBeanName the name of the containing (outer) bean* @see #registerDependentBean*/public void registerContainedBean(String containedBeanName, String containingBeanName) {synchronized (this.containedBeanMap) {Set<String> containedBeans =this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8));if (!containedBeans.add(containedBeanName)) {return;}}registerDependentBean(containedBeanName, containingBeanName);}/*** Register a dependent bean for the given bean,* to be destroyed before the given bean is destroyed.* @param beanName the name of the bean* @param dependentBeanName the name of the dependent bean*/public void registerDependentBean(String beanName, String dependentBeanName) {String canonicalName = canonicalName(beanName);synchronized (this.dependentBeanMap) {Set<String> dependentBeans =this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));if (!dependentBeans.add(dependentBeanName)) {return;}}synchronized (this.dependenciesForBeanMap) {Set<String> dependenciesForBean =this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));dependenciesForBean.add(canonicalName);}}/*** Determine whether the specified dependent bean has been registered as* dependent on the given bean or on any of its transitive dependencies.* @param beanName the name of the bean to check* @param dependentBeanName the name of the dependent bean* @since 4.0*/protected boolean isDependent(String beanName, String dependentBeanName) {synchronized (this.dependentBeanMap) {return isDependent(beanName, dependentBeanName, null);}}private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {if (alreadySeen != null && alreadySeen.contains(beanName)) {return false;}String canonicalName = canonicalName(beanName);Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans == null) {return false;}if (dependentBeans.contains(dependentBeanName)) {return true;}for (String transitiveDependency : dependentBeans) {if (alreadySeen == null) {alreadySeen = new HashSet<>();}alreadySeen.add(beanName);if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {return true;}}return false;}/*** Determine whether a dependent bean has been registered for the given name.* @param beanName the name of the bean to check*/protected boolean hasDependentBean(String beanName) {return this.dependentBeanMap.containsKey(beanName);}/*** Return the names of all beans which depend on the specified bean, if any.* @param beanName the name of the bean* @return the array of dependent bean names, or an empty array if none*/public String[] getDependentBeans(String beanName) {Set<String> dependentBeans = this.dependentBeanMap.get(beanName);if (dependentBeans == null) {return new String[0];}synchronized (this.dependentBeanMap) {return StringUtils.toStringArray(dependentBeans);}}/*** Return the names of all beans that the specified bean depends on, if any.* @param beanName the name of the bean* @return the array of names of beans which the bean depends on,* or an empty array if none*/public String[] getDependenciesForBean(String beanName) {Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(beanName);if (dependenciesForBean == null) {return new String[0];}synchronized (this.dependenciesForBeanMap) {return StringUtils.toStringArray(dependenciesForBean);}}public void destroySingletons() {if (logger.isDebugEnabled()) {logger.debug("Destroying singletons in " + this);}synchronized (this.singletonObjects) {this.singletonsCurrentlyInDestruction = true;}String[] disposableBeanNames;synchronized (this.disposableBeans) {disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());}for (int i = disposableBeanNames.length - 1; i >= 0; i--) {destroySingleton(disposableBeanNames[i]);}this.containedBeanMap.clear();this.dependentBeanMap.clear();this.dependenciesForBeanMap.clear();clearSingletonCache();}/*** Clear all cached singleton instances in this registry.* @since 4.3.15*/protected void clearSingletonCache() {synchronized (this.singletonObjects) {this.singletonObjects.clear();this.singletonFactories.clear();this.earlySingletonObjects.clear();this.registeredSingletons.clear();this.singletonsCurrentlyInDestruction = false;}}/*** Destroy the given bean. Delegates to {@code destroyBean}* if a corresponding disposable bean instance is found.* @param beanName the name of the bean* @see #destroyBean*/public void destroySingleton(String beanName) {// Remove a registered singleton of the given name, if any.removeSingleton(beanName);// Destroy the corresponding DisposableBean instance.DisposableBean disposableBean;synchronized (this.disposableBeans) {disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);}destroyBean(beanName, disposableBean);}/*** Destroy the given bean. Must destroy beans that depend on the given* bean before the bean itself. Should not throw any exceptions.* @param beanName the name of the bean* @param bean the bean instance to destroy*/protected void destroyBean(String beanName, @Nullable DisposableBean bean) {// Trigger destruction of dependent beans first...Set<String> dependencies;synchronized (this.dependentBeanMap) {// Within full synchronization in order to guarantee a disconnected Setdependencies = this.dependentBeanMap.remove(beanName);}if (dependencies != null) {if (logger.isDebugEnabled()) {logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);}for (String dependentBeanName : dependencies) {destroySingleton(dependentBeanName);}}// Actually destroy the bean now...if (bean != null) {try {bean.destroy();}catch (Throwable ex) {logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);}}// Trigger destruction of contained beans...Set<String> containedBeans;synchronized (this.containedBeanMap) {// Within full synchronization in order to guarantee a disconnected SetcontainedBeans = this.containedBeanMap.remove(beanName);}if (containedBeans != null) {for (String containedBeanName : containedBeans) {destroySingleton(containedBeanName);}}// Remove destroyed bean from other beans' dependencies.synchronized (this.dependentBeanMap) {for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {Map.Entry<String, Set<String>> entry = it.next();Set<String> dependenciesToClean = entry.getValue();dependenciesToClean.remove(beanName);if (dependenciesToClean.isEmpty()) {it.remove();}}}// Remove destroyed bean's prepared dependency information.this.dependenciesForBeanMap.remove(beanName);}/*** Exposes the singleton mutex to subclasses and external collaborators.* <p>Subclasses should synchronize on the given Object if they perform* any sort of extended singleton creation phase. In particular, subclasses* should <i>not</i> have their own mutexes involved in singleton creation,* to avoid the potential for deadlocks in lazy-init situations.*/@Overridepublic final Object getSingletonMutex() {return this.singletonObjects;}}
