1 16 17 package org.springframework.beans.factory.support; 18 19 import java.util.Collections ; 20 import java.util.HashMap ; 21 import java.util.HashSet ; 22 import java.util.Iterator ; 23 import java.util.Map ; 24 import java.util.Set ; 25 26 import org.apache.commons.logging.Log; 27 import org.apache.commons.logging.LogFactory; 28 29 import org.springframework.beans.factory.BeanCreationNotAllowedException; 30 import org.springframework.beans.factory.BeanCurrentlyInCreationException; 31 import org.springframework.beans.factory.DisposableBean; 32 import org.springframework.beans.factory.ObjectFactory; 33 import org.springframework.beans.factory.config.SingletonBeanRegistry; 34 import org.springframework.core.CollectionFactory; 35 import org.springframework.util.Assert; 36 import org.springframework.util.StringUtils; 37 38 69 public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry { 70 71 72 protected final Log logger = LogFactory.getLog(getClass()); 73 74 75 private final Map singletonCache = CollectionFactory.createLinkedMapIfPossible(16); 76 77 78 private final Set singletonsCurrentlyInCreation = Collections.synchronizedSet(new HashSet ()); 79 80 81 private boolean singletonsCurrentlyInDestruction = false; 82 83 84 private final Map disposableBeans = CollectionFactory.createLinkedMapIfPossible(16); 85 86 87 private final Map dependentBeanMap = new HashMap (); 88 89 90 public void registerSingleton(String beanName, Object sharedBean) throws IllegalStateException { 91 Assert.hasText(beanName, "'beanName' must not be empty"); 92 Assert.notNull(sharedBean, "Singleton object must not be null"); 93 synchronized (this.singletonCache) { 94 Object oldObject = this.singletonCache.get(beanName); 95 if (oldObject != null) { 96 throw new IllegalStateException ("Could not register object [" + sharedBean + 97 "] under bean name '" + beanName + "': there's already object [" + oldObject + " bound"); 98 } 99 addSingleton(beanName, sharedBean); 100 } 101 } 102 103 110 protected void addSingleton(String beanName, Object sharedBean) { 111 Assert.hasText(beanName, "'beanName' must not be empty"); 112 synchronized (this.singletonCache) { 113 this.singletonCache.put(beanName, sharedBean); 114 } 115 } 116 117 public Object getSingleton(String beanName) { 118 synchronized (this.singletonCache) { 119 return this.singletonCache.get(beanName); 120 } 121 } 122 123 129 public Object getSingleton(String beanName, ObjectFactory singletonFactory) { 130 synchronized (this.singletonCache) { 131 Object sharedInstance = this.singletonCache.get(beanName); 133 if (sharedInstance == null) { 134 if (this.singletonsCurrentlyInDestruction) { 135 throw new BeanCreationNotAllowedException(beanName, 136 "Singleton bean creation not allowed while the singletons of this factory are in destruction " + 137 "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); 138 } 139 if (logger.isDebugEnabled()) { 140 logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); 141 } 142 beforeSingletonCreation(beanName); 143 try { 144 sharedInstance = singletonFactory.getObject(); 145 } 146 finally { 147 afterSingletonCreation(beanName); 148 } 149 addSingleton(beanName, sharedInstance); 150 } 151 return sharedInstance; 152 } 153 } 154 155 160 protected void removeSingleton(String beanName) { 161 Assert.hasText(beanName, "'beanName' must not be empty"); 162 this.singletonCache.remove(beanName); 163 } 164 165 public boolean containsSingleton(String beanName) { 166 Assert.hasText(beanName, "'beanName' must not be empty"); 167 synchronized (this.singletonCache) { 168 return this.singletonCache.containsKey(beanName); 169 } 170 } 171 172 public String [] getSingletonNames() { 173 synchronized (this.singletonCache) { 174 return StringUtils.toStringArray(this.singletonCache.keySet()); 175 } 176 } 177 178 public int getSingletonCount() { 179 synchronized (this.singletonCache) { 180 return this.singletonCache.size(); 181 } 182 } 183 184 185 191 protected void beforeSingletonCreation(String beanName) { 192 if (!this.singletonsCurrentlyInCreation.add(beanName)) { 193 throw new BeanCurrentlyInCreationException(beanName); 194 } 195 } 196 197 203 protected void afterSingletonCreation(String beanName) { 204 if (!this.singletonsCurrentlyInCreation.remove(beanName)) { 205 throw new IllegalStateException ("Singleton '" + beanName + "' isn't currently in creation"); 206 } 207 } 208 209 214 public final boolean isSingletonCurrentlyInCreation(String beanName) { 215 return this.singletonsCurrentlyInCreation.contains(beanName); 216 } 217 218 219 228 public void registerDisposableBean(String beanName, DisposableBean bean) { 229 synchronized (this.disposableBeans) { 230 this.disposableBeans.put(beanName, bean); 231 } 232 } 233 234 240 public void registerDependentBean(String beanName, String dependentBeanName) { 241 synchronized (this.dependentBeanMap) { 242 Set dependencies = (Set ) this.dependentBeanMap.get(beanName); 243 if (dependencies == null) { 244 dependencies = CollectionFactory.createLinkedSetIfPossible(8); 245 this.dependentBeanMap.put(beanName, dependencies); 246 } 247 dependencies.add(dependentBeanName); 248 } 249 } 250 251 255 protected boolean hasDependentBean(String beanName) { 256 synchronized (this.dependentBeanMap) { 257 return this.dependentBeanMap.containsKey(beanName); 258 } 259 } 260 261 266 protected Set getDependentBeans(String beanName) { 267 synchronized (this.dependentBeanMap) { 268 return Collections.unmodifiableSet((Set ) this.dependentBeanMap.get(beanName)); 269 } 270 } 271 272 public void destroySingletons() { 273 if (logger.isInfoEnabled()) { 274 logger.info("Destroying singletons in " + this); 275 } 276 synchronized (this.singletonCache) { 277 this.singletonsCurrentlyInDestruction = true; 278 } 279 synchronized (this.disposableBeans) { 280 String [] disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); 281 for (int i = disposableBeanNames.length - 1; i >= 0; i--) { 282 destroySingleton(disposableBeanNames[i]); 283 } 284 } 285 synchronized (this.singletonCache) { 286 this.singletonCache.clear(); 287 this.singletonsCurrentlyInDestruction = false; 288 } 289 } 290 291 297 public void destroySingleton(String beanName) { 298 synchronized (this.singletonCache) { 299 removeSingleton(beanName); 301 } 302 303 DisposableBean disposableBean = null; 305 synchronized (this.disposableBeans) { 306 disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); 307 } 308 destroyBean(beanName, disposableBean); 309 } 310 311 317 protected void destroyBean(String beanName, DisposableBean bean) { 318 Set dependencies = null; 319 synchronized (this.dependentBeanMap) { 320 dependencies = (Set ) this.dependentBeanMap.remove(beanName); 321 } 322 323 if (dependencies != null) { 324 if (logger.isDebugEnabled()) { 325 logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies); 326 } 327 for (Iterator it = dependencies.iterator(); it.hasNext();) { 328 String dependentBeanName = (String ) it.next(); 329 destroySingleton(dependentBeanName); 330 } 331 } 332 333 if (bean != null) { 334 try { 335 bean.destroy(); 336 } 337 catch (Throwable ex) { 338 logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex); 339 } 340 } 341 } 342 343 350 protected final Object getSingletonMutex() { 351 return this.singletonCache; 352 } 353 354 } 355 | Popular Tags |