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

一、类继承关系

  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12747730/1637720649178-3e73e573-87c9-4498-b9d9-12f0e62a9368.png#clientId=ua1080df1-5858-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=307&id=u1657407b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=614&originWidth=1118&originalType=binary&ratio=1&rotation=0&showTitle=false&size=45424&status=done&style=none&taskId=u3dd02e33-34c5-4093-ad16-bda8cf7d356&title=&width=559)

二、核心类和对象

1.

Spring 三级缓存模块中核心的类:defaultSingletonBeanRegistry 三级缓存对象:

  1. singletonObjects :一级缓存,主要存储创建后完整的bean对象
  2. singletonFactories: 三级缓存,主要存储创建后的beanFactroy对象,并存储真正的bean对象
  3. earlySingletonObjects: 二级缓存,存储bean对象
  4. registeredSingletons: 已经完成注册的对象

核心方法:

  1. registerSingleton(): 注册单例对象
  2. addSingleton(): 添加单例对象到一级缓存中
    1. 添加对象进入到一级缓存
    2. 删除二、三级缓存对象
    3. 添加bean 对象 Set 集合
  3. getSingleton(): 通过beanName 获取 bean对象

  1. 基本对象属性 ```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 =

    1. Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    /* Names of beans currently excluded from in creation checks / private final Set inCreationCheckExclusions =

    1. 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);

}

  1. 3. 基本方法
  2. 1. 注册单列对象
  3. ```java
  4. /**
  5. * 注册单列对象
  6. * @param beanName the name of the bean
  7. * @param singletonObject the existing singleton object
  8. * @throws IllegalStateException
  9. */
  10. @Override
  11. public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
  12. Assert.notNull(beanName, "Bean name must not be null");
  13. Assert.notNull(singletonObject, "Singleton object must not be null");
  14. synchronized (this.singletonObjects) {
  15. Object oldObject = this.singletonObjects.get(beanName);
  16. if (oldObject != null) {
  17. throw new IllegalStateException("Could not register object [" + singletonObject +
  18. "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
  19. }
  20. addSingleton(beanName, singletonObject);
  21. }
  22. }
  23. /**
  24. * Add the given singleton object to the singleton cache of this factory.
  25. * <p>To be called for eager registration of singletons.
  26. * @param beanName the name of the bean
  27. * @param singletonObject the singleton object
  28. */
  29. protected void addSingleton(String beanName, Object singletonObject) {
  30. synchronized (this.singletonObjects) {
  31. this.singletonObjects.put(beanName, singletonObject);
  32. this.singletonFactories.remove(beanName);
  33. this.earlySingletonObjects.remove(beanName);
  34. this.registeredSingletons.add(beanName);
  35. }
  36. }
  37. /**
  38. * Add the given singleton factory for building the specified singleton
  39. * if necessary.
  40. * <p>To be called for eager registration of singletons, e.g. to be able to
  41. * resolve circular references.
  42. * @param beanName the name of the bean
  43. * @param singletonFactory the factory for the singleton object
  44. */
  45. protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
  46. Assert.notNull(singletonFactory, "Singleton factory must not be null");
  47. synchronized (this.singletonObjects) {
  48. if (!this.singletonObjects.containsKey(beanName)) {
  49. this.singletonFactories.put(beanName, singletonFactory);
  50. this.earlySingletonObjects.remove(beanName);
  51. this.registeredSingletons.add(beanName);
  52. }
  53. }
  54. }
  1. 获取对象 ```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)) {
      1. synchronized (this.singletonObjects) {
      2. singletonObject = this.earlySingletonObjects.get(beanName);
      3. if (singletonObject == null && allowEarlyReference) {
      4. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
      5. if (singletonFactory != null) {
      6. singletonObject = singletonFactory.getObject();
      7. this.earlySingletonObjects.put(beanName, singletonObject);
      8. this.singletonFactories.remove(beanName);
      9. }
      10. }
      11. }
      } 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) {
      1. Object singletonObject = this.singletonObjects.get(beanName);
      2. if (singletonObject == null) {
      3. if (this.singletonsCurrentlyInDestruction) {
      4. throw new BeanCreationNotAllowedException(beanName,
      5. "Singleton bean creation not allowed while singletons of this factory are in destruction " +
      6. "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
      7. }
      8. if (logger.isDebugEnabled()) {
      9. logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
      10. }
      11. beforeSingletonCreation(beanName);
      12. boolean newSingleton = false;
      13. boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
      14. if (recordSuppressedExceptions) {
      15. this.suppressedExceptions = new LinkedHashSet<>();
      16. }
      17. try {
      18. singletonObject = singletonFactory.getObject();
      19. newSingleton = true;
      20. }
      21. catch (IllegalStateException ex) {
      22. // Has the singleton object implicitly appeared in the meantime ->
      23. // if yes, proceed with it since the exception indicates that state.
      24. singletonObject = this.singletonObjects.get(beanName);
      25. if (singletonObject == null) {
      26. throw ex;
      27. }
      28. }
      29. catch (BeanCreationException ex) {
      30. if (recordSuppressedExceptions) {
      31. for (Exception suppressedException : this.suppressedExceptions) {
      32. ex.addRelatedCause(suppressedException);
      33. }
      34. }
      35. throw ex;
      36. }
      37. finally {
      38. if (recordSuppressedExceptions) {
      39. this.suppressedExceptions = null;
      40. }
      41. afterSingletonCreation(beanName);
      42. }
      43. if (newSingleton) {
      44. addSingleton(beanName, singletonObject);
      45. }
      46. }
      47. return singletonObject;
      } }
  1. 3. a
  2. 3. <br />
  3. 3. <br />
  4. 4. 全部代码
  5. ```java
  6. public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
  7. /** Cache of singleton objects: bean name --> bean instance */
  8. /** 一级缓存 **/
  9. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  10. /** Cache of singleton factories: bean name --> ObjectFactory */
  11. /** 三级缓存 **/
  12. private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  13. /** Cache of early singleton objects: bean name --> bean instance */
  14. /** 二级缓存 **/
  15. private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  16. /** Set of registered singletons, containing the bean names in registration order */
  17. // 所有单列对象集合,并按照beanName 进行排序
  18. private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
  19. /** Names of beans that are currently in creation */
  20. private final Set<String> singletonsCurrentlyInCreation =
  21. Collections.newSetFromMap(new ConcurrentHashMap<>(16));
  22. /** Names of beans currently excluded from in creation checks */
  23. private final Set<String> inCreationCheckExclusions =
  24. Collections.newSetFromMap(new ConcurrentHashMap<>(16));
  25. /** List of suppressed Exceptions, available for associating related causes */
  26. @Nullable
  27. private Set<Exception> suppressedExceptions;
  28. /** Flag that indicates whether we're currently within destroySingletons */
  29. private boolean singletonsCurrentlyInDestruction = false;
  30. /** Disposable bean instances: bean name --> disposable instance */
  31. private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
  32. /** Map between containing bean names: bean name --> Set of bean names that the bean contains */
  33. private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
  34. /** Map between dependent bean names: bean name --> Set of dependent bean names */
  35. private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
  36. /** Map between depending bean names: bean name --> Set of bean names for the bean's dependencies */
  37. private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
  38. @Override
  39. public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
  40. Assert.notNull(beanName, "Bean name must not be null");
  41. Assert.notNull(singletonObject, "Singleton object must not be null");
  42. synchronized (this.singletonObjects) {
  43. Object oldObject = this.singletonObjects.get(beanName);
  44. if (oldObject != null) {
  45. throw new IllegalStateException("Could not register object [" + singletonObject +
  46. "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
  47. }
  48. addSingleton(beanName, singletonObject);
  49. }
  50. }
  51. /**
  52. * Add the given singleton object to the singleton cache of this factory.
  53. * <p>To be called for eager registration of singletons.
  54. * @param beanName the name of the bean
  55. * @param singletonObject the singleton object
  56. */
  57. protected void addSingleton(String beanName, Object singletonObject) {
  58. synchronized (this.singletonObjects) {
  59. this.singletonObjects.put(beanName, singletonObject);
  60. this.singletonFactories.remove(beanName);
  61. this.earlySingletonObjects.remove(beanName);
  62. this.registeredSingletons.add(beanName);
  63. }
  64. }
  65. /**
  66. * Add the given singleton factory for building the specified singleton
  67. * if necessary.
  68. * <p>To be called for eager registration of singletons, e.g. to be able to
  69. * resolve circular references.
  70. * @param beanName the name of the bean
  71. * @param singletonFactory the factory for the singleton object
  72. */
  73. protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
  74. Assert.notNull(singletonFactory, "Singleton factory must not be null");
  75. synchronized (this.singletonObjects) {
  76. if (!this.singletonObjects.containsKey(beanName)) {
  77. this.singletonFactories.put(beanName, singletonFactory);
  78. this.earlySingletonObjects.remove(beanName);
  79. this.registeredSingletons.add(beanName);
  80. }
  81. }
  82. }
  83. @Override
  84. @Nullable
  85. public Object getSingleton(String beanName) {
  86. return getSingleton(beanName, true);
  87. }
  88. /**
  89. * Return the (raw) singleton object registered under the given name.
  90. * <p>Checks already instantiated singletons and also allows for an early
  91. * reference to a currently created singleton (resolving a circular reference).
  92. * @param beanName the name of the bean to look for
  93. * @param allowEarlyReference whether early references should be created or not
  94. * @return the registered singleton object, or {@code null} if none found
  95. */
  96. @Nullable
  97. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  98. Object singletonObject = this.singletonObjects.get(beanName);
  99. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  100. synchronized (this.singletonObjects) {
  101. singletonObject = this.earlySingletonObjects.get(beanName);
  102. if (singletonObject == null && allowEarlyReference) {
  103. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  104. if (singletonFactory != null) {
  105. singletonObject = singletonFactory.getObject();
  106. this.earlySingletonObjects.put(beanName, singletonObject);
  107. this.singletonFactories.remove(beanName);
  108. }
  109. }
  110. }
  111. }
  112. return singletonObject;
  113. }
  114. /**
  115. * Return the (raw) singleton object registered under the given name,
  116. * creating and registering a new one if none registered yet.
  117. * @param beanName the name of the bean
  118. * @param singletonFactory the ObjectFactory to lazily create the singleton
  119. * with, if necessary
  120. * @return the registered singleton object
  121. */
  122. public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
  123. Assert.notNull(beanName, "Bean name must not be null");
  124. synchronized (this.singletonObjects) {
  125. Object singletonObject = this.singletonObjects.get(beanName);
  126. if (singletonObject == null) {
  127. if (this.singletonsCurrentlyInDestruction) {
  128. throw new BeanCreationNotAllowedException(beanName,
  129. "Singleton bean creation not allowed while singletons of this factory are in destruction " +
  130. "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
  131. }
  132. if (logger.isDebugEnabled()) {
  133. logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
  134. }
  135. beforeSingletonCreation(beanName);
  136. boolean newSingleton = false;
  137. boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
  138. if (recordSuppressedExceptions) {
  139. this.suppressedExceptions = new LinkedHashSet<>();
  140. }
  141. try {
  142. singletonObject = singletonFactory.getObject();
  143. newSingleton = true;
  144. }
  145. catch (IllegalStateException ex) {
  146. // Has the singleton object implicitly appeared in the meantime ->
  147. // if yes, proceed with it since the exception indicates that state.
  148. singletonObject = this.singletonObjects.get(beanName);
  149. if (singletonObject == null) {
  150. throw ex;
  151. }
  152. }
  153. catch (BeanCreationException ex) {
  154. if (recordSuppressedExceptions) {
  155. for (Exception suppressedException : this.suppressedExceptions) {
  156. ex.addRelatedCause(suppressedException);
  157. }
  158. }
  159. throw ex;
  160. }
  161. finally {
  162. if (recordSuppressedExceptions) {
  163. this.suppressedExceptions = null;
  164. }
  165. afterSingletonCreation(beanName);
  166. }
  167. if (newSingleton) {
  168. addSingleton(beanName, singletonObject);
  169. }
  170. }
  171. return singletonObject;
  172. }
  173. }
  174. /**
  175. * Register an Exception that happened to get suppressed during the creation of a
  176. * singleton bean instance, e.g. a temporary circular reference resolution problem.
  177. * @param ex the Exception to register
  178. */
  179. protected void onSuppressedException(Exception ex) {
  180. synchronized (this.singletonObjects) {
  181. if (this.suppressedExceptions != null) {
  182. this.suppressedExceptions.add(ex);
  183. }
  184. }
  185. }
  186. /**
  187. * Remove the bean with the given name from the singleton cache of this factory,
  188. * to be able to clean up eager registration of a singleton if creation failed.
  189. * @param beanName the name of the bean
  190. * @see #getSingletonMutex()
  191. */
  192. protected void removeSingleton(String beanName) {
  193. synchronized (this.singletonObjects) {
  194. this.singletonObjects.remove(beanName);
  195. this.singletonFactories.remove(beanName);
  196. this.earlySingletonObjects.remove(beanName);
  197. this.registeredSingletons.remove(beanName);
  198. }
  199. }
  200. @Override
  201. public boolean containsSingleton(String beanName) {
  202. return this.singletonObjects.containsKey(beanName);
  203. }
  204. @Override
  205. public String[] getSingletonNames() {
  206. synchronized (this.singletonObjects) {
  207. return StringUtils.toStringArray(this.registeredSingletons);
  208. }
  209. }
  210. @Override
  211. public int getSingletonCount() {
  212. synchronized (this.singletonObjects) {
  213. return this.registeredSingletons.size();
  214. }
  215. }
  216. public void setCurrentlyInCreation(String beanName, boolean inCreation) {
  217. Assert.notNull(beanName, "Bean name must not be null");
  218. if (!inCreation) {
  219. this.inCreationCheckExclusions.add(beanName);
  220. }
  221. else {
  222. this.inCreationCheckExclusions.remove(beanName);
  223. }
  224. }
  225. public boolean isCurrentlyInCreation(String beanName) {
  226. Assert.notNull(beanName, "Bean name must not be null");
  227. return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName));
  228. }
  229. protected boolean isActuallyInCreation(String beanName) {
  230. return isSingletonCurrentlyInCreation(beanName);
  231. }
  232. /**
  233. * Return whether the specified singleton bean is currently in creation
  234. * (within the entire factory).
  235. * @param beanName the name of the bean
  236. */
  237. public boolean isSingletonCurrentlyInCreation(String beanName) {
  238. return this.singletonsCurrentlyInCreation.contains(beanName);
  239. }
  240. /**
  241. * Callback before singleton creation.
  242. * <p>The default implementation register the singleton as currently in creation.
  243. * @param beanName the name of the singleton about to be created
  244. * @see #isSingletonCurrentlyInCreation
  245. */
  246. protected void beforeSingletonCreation(String beanName) {
  247. if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
  248. throw new BeanCurrentlyInCreationException(beanName);
  249. }
  250. }
  251. /**
  252. * Callback after singleton creation.
  253. * <p>The default implementation marks the singleton as not in creation anymore.
  254. * @param beanName the name of the singleton that has been created
  255. * @see #isSingletonCurrentlyInCreation
  256. */
  257. protected void afterSingletonCreation(String beanName) {
  258. if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
  259. throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
  260. }
  261. }
  262. /**
  263. * Add the given bean to the list of disposable beans in this registry.
  264. * <p>Disposable beans usually correspond to registered singletons,
  265. * matching the bean name but potentially being a different instance
  266. * (for example, a DisposableBean adapter for a singleton that does not
  267. * naturally implement Spring's DisposableBean interface).
  268. * @param beanName the name of the bean
  269. * @param bean the bean instance
  270. */
  271. public void registerDisposableBean(String beanName, DisposableBean bean) {
  272. synchronized (this.disposableBeans) {
  273. this.disposableBeans.put(beanName, bean);
  274. }
  275. }
  276. /**
  277. * Register a containment relationship between two beans,
  278. * e.g. between an inner bean and its containing outer bean.
  279. * <p>Also registers the containing bean as dependent on the contained bean
  280. * in terms of destruction order.
  281. * @param containedBeanName the name of the contained (inner) bean
  282. * @param containingBeanName the name of the containing (outer) bean
  283. * @see #registerDependentBean
  284. */
  285. public void registerContainedBean(String containedBeanName, String containingBeanName) {
  286. synchronized (this.containedBeanMap) {
  287. Set<String> containedBeans =
  288. this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8));
  289. if (!containedBeans.add(containedBeanName)) {
  290. return;
  291. }
  292. }
  293. registerDependentBean(containedBeanName, containingBeanName);
  294. }
  295. /**
  296. * Register a dependent bean for the given bean,
  297. * to be destroyed before the given bean is destroyed.
  298. * @param beanName the name of the bean
  299. * @param dependentBeanName the name of the dependent bean
  300. */
  301. public void registerDependentBean(String beanName, String dependentBeanName) {
  302. String canonicalName = canonicalName(beanName);
  303. synchronized (this.dependentBeanMap) {
  304. Set<String> dependentBeans =
  305. this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
  306. if (!dependentBeans.add(dependentBeanName)) {
  307. return;
  308. }
  309. }
  310. synchronized (this.dependenciesForBeanMap) {
  311. Set<String> dependenciesForBean =
  312. this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
  313. dependenciesForBean.add(canonicalName);
  314. }
  315. }
  316. /**
  317. * Determine whether the specified dependent bean has been registered as
  318. * dependent on the given bean or on any of its transitive dependencies.
  319. * @param beanName the name of the bean to check
  320. * @param dependentBeanName the name of the dependent bean
  321. * @since 4.0
  322. */
  323. protected boolean isDependent(String beanName, String dependentBeanName) {
  324. synchronized (this.dependentBeanMap) {
  325. return isDependent(beanName, dependentBeanName, null);
  326. }
  327. }
  328. private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
  329. if (alreadySeen != null && alreadySeen.contains(beanName)) {
  330. return false;
  331. }
  332. String canonicalName = canonicalName(beanName);
  333. Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
  334. if (dependentBeans == null) {
  335. return false;
  336. }
  337. if (dependentBeans.contains(dependentBeanName)) {
  338. return true;
  339. }
  340. for (String transitiveDependency : dependentBeans) {
  341. if (alreadySeen == null) {
  342. alreadySeen = new HashSet<>();
  343. }
  344. alreadySeen.add(beanName);
  345. if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
  346. return true;
  347. }
  348. }
  349. return false;
  350. }
  351. /**
  352. * Determine whether a dependent bean has been registered for the given name.
  353. * @param beanName the name of the bean to check
  354. */
  355. protected boolean hasDependentBean(String beanName) {
  356. return this.dependentBeanMap.containsKey(beanName);
  357. }
  358. /**
  359. * Return the names of all beans which depend on the specified bean, if any.
  360. * @param beanName the name of the bean
  361. * @return the array of dependent bean names, or an empty array if none
  362. */
  363. public String[] getDependentBeans(String beanName) {
  364. Set<String> dependentBeans = this.dependentBeanMap.get(beanName);
  365. if (dependentBeans == null) {
  366. return new String[0];
  367. }
  368. synchronized (this.dependentBeanMap) {
  369. return StringUtils.toStringArray(dependentBeans);
  370. }
  371. }
  372. /**
  373. * Return the names of all beans that the specified bean depends on, if any.
  374. * @param beanName the name of the bean
  375. * @return the array of names of beans which the bean depends on,
  376. * or an empty array if none
  377. */
  378. public String[] getDependenciesForBean(String beanName) {
  379. Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(beanName);
  380. if (dependenciesForBean == null) {
  381. return new String[0];
  382. }
  383. synchronized (this.dependenciesForBeanMap) {
  384. return StringUtils.toStringArray(dependenciesForBean);
  385. }
  386. }
  387. public void destroySingletons() {
  388. if (logger.isDebugEnabled()) {
  389. logger.debug("Destroying singletons in " + this);
  390. }
  391. synchronized (this.singletonObjects) {
  392. this.singletonsCurrentlyInDestruction = true;
  393. }
  394. String[] disposableBeanNames;
  395. synchronized (this.disposableBeans) {
  396. disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
  397. }
  398. for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
  399. destroySingleton(disposableBeanNames[i]);
  400. }
  401. this.containedBeanMap.clear();
  402. this.dependentBeanMap.clear();
  403. this.dependenciesForBeanMap.clear();
  404. clearSingletonCache();
  405. }
  406. /**
  407. * Clear all cached singleton instances in this registry.
  408. * @since 4.3.15
  409. */
  410. protected void clearSingletonCache() {
  411. synchronized (this.singletonObjects) {
  412. this.singletonObjects.clear();
  413. this.singletonFactories.clear();
  414. this.earlySingletonObjects.clear();
  415. this.registeredSingletons.clear();
  416. this.singletonsCurrentlyInDestruction = false;
  417. }
  418. }
  419. /**
  420. * Destroy the given bean. Delegates to {@code destroyBean}
  421. * if a corresponding disposable bean instance is found.
  422. * @param beanName the name of the bean
  423. * @see #destroyBean
  424. */
  425. public void destroySingleton(String beanName) {
  426. // Remove a registered singleton of the given name, if any.
  427. removeSingleton(beanName);
  428. // Destroy the corresponding DisposableBean instance.
  429. DisposableBean disposableBean;
  430. synchronized (this.disposableBeans) {
  431. disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
  432. }
  433. destroyBean(beanName, disposableBean);
  434. }
  435. /**
  436. * Destroy the given bean. Must destroy beans that depend on the given
  437. * bean before the bean itself. Should not throw any exceptions.
  438. * @param beanName the name of the bean
  439. * @param bean the bean instance to destroy
  440. */
  441. protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
  442. // Trigger destruction of dependent beans first...
  443. Set<String> dependencies;
  444. synchronized (this.dependentBeanMap) {
  445. // Within full synchronization in order to guarantee a disconnected Set
  446. dependencies = this.dependentBeanMap.remove(beanName);
  447. }
  448. if (dependencies != null) {
  449. if (logger.isDebugEnabled()) {
  450. logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
  451. }
  452. for (String dependentBeanName : dependencies) {
  453. destroySingleton(dependentBeanName);
  454. }
  455. }
  456. // Actually destroy the bean now...
  457. if (bean != null) {
  458. try {
  459. bean.destroy();
  460. }
  461. catch (Throwable ex) {
  462. logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
  463. }
  464. }
  465. // Trigger destruction of contained beans...
  466. Set<String> containedBeans;
  467. synchronized (this.containedBeanMap) {
  468. // Within full synchronization in order to guarantee a disconnected Set
  469. containedBeans = this.containedBeanMap.remove(beanName);
  470. }
  471. if (containedBeans != null) {
  472. for (String containedBeanName : containedBeans) {
  473. destroySingleton(containedBeanName);
  474. }
  475. }
  476. // Remove destroyed bean from other beans' dependencies.
  477. synchronized (this.dependentBeanMap) {
  478. for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
  479. Map.Entry<String, Set<String>> entry = it.next();
  480. Set<String> dependenciesToClean = entry.getValue();
  481. dependenciesToClean.remove(beanName);
  482. if (dependenciesToClean.isEmpty()) {
  483. it.remove();
  484. }
  485. }
  486. }
  487. // Remove destroyed bean's prepared dependency information.
  488. this.dependenciesForBeanMap.remove(beanName);
  489. }
  490. /**
  491. * Exposes the singleton mutex to subclasses and external collaborators.
  492. * <p>Subclasses should synchronize on the given Object if they perform
  493. * any sort of extended singleton creation phase. In particular, subclasses
  494. * should <i>not</i> have their own mutexes involved in singleton creation,
  495. * to avoid the potential for deadlocks in lazy-init situations.
  496. */
  497. @Override
  498. public final Object getSingletonMutex() {
  499. return this.singletonObjects;
  500. }
  501. }