1 16 17 package org.springframework.beans.factory.access; 18 19 import java.io.IOException ; 20 import java.util.HashMap ; 21 import java.util.Map ; 22 23 import org.apache.commons.logging.Log; 24 import org.apache.commons.logging.LogFactory; 25 26 import org.springframework.beans.BeansException; 27 import org.springframework.beans.FatalBeanException; 28 import org.springframework.beans.factory.BeanDefinitionStoreException; 29 import org.springframework.beans.factory.BeanFactory; 30 import org.springframework.beans.factory.config.ConfigurableBeanFactory; 31 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 32 import org.springframework.beans.factory.support.DefaultListableBeanFactory; 33 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; 34 import org.springframework.core.io.Resource; 35 import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 36 import org.springframework.core.io.support.ResourcePatternResolver; 37 38 270 public class SingletonBeanFactoryLocator implements BeanFactoryLocator { 271 272 private static final String BEANS_REFS_XML_NAME = "classpath*:beanRefFactory.xml"; 273 274 protected static final Log logger = LogFactory.getLog(SingletonBeanFactoryLocator.class); 275 276 private static Map instances = new HashMap (); 278 279 280 286 public static BeanFactoryLocator getInstance() throws FatalBeanException { 287 return getInstance(BEANS_REFS_XML_NAME); 288 } 289 290 303 public static BeanFactoryLocator getInstance(String selector) throws FatalBeanException { 304 if (selector.indexOf(':') == -1) { 307 selector = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + selector; 308 } 309 310 synchronized (instances) { 311 if (logger.isTraceEnabled()) { 312 logger.trace("SingletonBeanFactoryLocator.getInstance(): instances.hashCode=" + 313 instances.hashCode() + ", instances=" + instances); 314 } 315 BeanFactoryLocator bfl = (BeanFactoryLocator) instances.get(selector); 316 if (bfl == null) { 317 bfl = new SingletonBeanFactoryLocator(selector); 318 instances.put(selector, bfl); 319 } 320 return bfl; 321 } 322 } 323 324 325 private final Map bfgInstancesByKey = new HashMap (); 327 328 private final Map bfgInstancesByObj = new HashMap (); 329 330 private final String resourceName; 331 332 333 338 protected SingletonBeanFactoryLocator() { 339 this.resourceName = BEANS_REFS_XML_NAME; 340 } 341 342 348 protected SingletonBeanFactoryLocator(String resourceName) { 349 this.resourceName = resourceName; 350 } 351 352 public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException { 353 synchronized (this.bfgInstancesByKey) { 354 BeanFactoryGroup bfg = (BeanFactoryGroup) this.bfgInstancesByKey.get(this.resourceName); 355 356 if (bfg != null) { 357 bfg.refCount++; 358 } 359 else { 360 if (logger.isTraceEnabled()) { 362 logger.trace("Factory group with resource name [" + this.resourceName + 363 "] requested. Creating new instance."); 364 } 365 366 BeanFactory groupContext = createDefinition(this.resourceName, factoryKey); 368 369 bfg = new BeanFactoryGroup(); 371 bfg.definition = groupContext; 372 bfg.refCount = 1; 373 this.bfgInstancesByKey.put(this.resourceName, bfg); 374 this.bfgInstancesByObj.put(groupContext, bfg); 375 376 try { 381 initializeDefinition(groupContext); 382 } 383 catch (BeansException ex) { 384 throw new BootstrapException("Unable to initialize group definition. " + 385 "Group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]", ex); 386 } 387 } 388 389 final BeanFactory groupContext = bfg.definition; 390 391 String beanName = factoryKey; 392 Object bean; 393 try { 394 bean = groupContext.getBean(beanName); 395 if (bean instanceof String ) { 396 logger.warn("You're using the deprecated alias-through-String-bean feature, " + 397 "which will be removed as of Spring 2.1. It is recommended to replace this " + 398 "with an <alias> tag (see SingletonBeanFactoryLocator javadoc)."); 399 beanName = (String ) bean; 400 bean = groupContext.getBean(beanName); 401 } 402 } 403 catch (BeansException ex) { 404 throw new BootstrapException("Unable to return specified BeanFactory instance: factory key [" + 405 factoryKey + "], from group with resource name [" + this.resourceName + "]", ex); 406 } 407 408 if (!(bean instanceof BeanFactory)) { 409 throw new BootstrapException("Bean '" + beanName + "' is not a BeanFactory: factory key [" + 410 factoryKey + "], from group with resource name [" + this.resourceName + "]"); 411 } 412 413 final BeanFactory beanFactory = (BeanFactory) bean; 414 415 return new BeanFactoryReference() { 416 417 BeanFactory groupContextRef; 418 419 { 421 this.groupContextRef = groupContext; 422 } 423 424 public BeanFactory getFactory() { 425 return beanFactory; 426 } 427 428 public void release() throws FatalBeanException { 430 synchronized (bfgInstancesByKey) { 431 BeanFactory savedRef = this.groupContextRef; 432 if (savedRef != null) { 433 this.groupContextRef = null; 434 BeanFactoryGroup bfg = (BeanFactoryGroup) bfgInstancesByObj.get(savedRef); 435 if (bfg != null) { 436 bfg.refCount--; 437 if (bfg.refCount == 0) { 438 destroyDefinition(savedRef, resourceName); 439 bfgInstancesByKey.remove(resourceName); 440 bfgInstancesByObj.remove(savedRef); 441 } 442 } 443 else { 444 logger.warn("Tried to release a SingletonBeanFactoryLocator group definition " + 446 "more times than it has actually been used. Resource name [" + resourceName + "]"); 447 } 448 } 449 } 450 } 451 }; 452 } 453 } 454 455 464 protected BeanFactory createDefinition(String resourceName, String factoryKey) throws BeansException { 465 DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); 466 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); 467 ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); 468 469 try { 470 Resource[] configResources = resourcePatternResolver.getResources(resourceName); 471 if (configResources.length == 0) { 472 throw new FatalBeanException("Unable to find resource for specified definition. " + 473 "Group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]"); 474 } 475 reader.loadBeanDefinitions(configResources); 476 } 477 catch (IOException ex) { 478 throw new BeanDefinitionStoreException( 479 "Error accessing bean definition resource [" + this.resourceName + "]", ex); 480 } 481 catch (BeanDefinitionStoreException ex) { 482 throw new FatalBeanException("Unable to load group definition: " + 483 "group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]", ex); 484 } 485 486 return factory; 487 } 488 489 495 protected void initializeDefinition(BeanFactory groupDef) throws BeansException { 496 if (groupDef instanceof ConfigurableListableBeanFactory) { 497 ((ConfigurableListableBeanFactory) groupDef).preInstantiateSingletons(); 498 } 499 } 500 501 504 protected void destroyDefinition(BeanFactory groupDef, String resourceName) throws BeansException { 505 if (groupDef instanceof ConfigurableBeanFactory) { 506 if (logger.isTraceEnabled()) { 507 logger.trace("Factory group with resource name '" + resourceName + 508 "' being released, as there are no more references to it."); 509 } 510 ((ConfigurableBeanFactory) groupDef).destroySingletons(); 511 } 512 } 513 514 515 518 private static class BeanFactoryGroup { 519 520 private BeanFactory definition; 521 522 private int refCount = 0; 523 } 524 525 } 526 | Popular Tags |