Home » Spring-Framework-090522 » org.springframework » beans » factory » access » [javadoc | source]

    1   /*
    2    * Copyright 2002-2008 the original author or authors.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   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.BeanFactoryUtils;
   31   import org.springframework.beans.factory.ListableBeanFactory;
   32   import org.springframework.beans.factory.config.ConfigurableBeanFactory;
   33   import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
   34   import org.springframework.beans.factory.support.DefaultListableBeanFactory;
   35   import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
   36   import org.springframework.core.io.Resource;
   37   import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
   38   import org.springframework.core.io.support.ResourcePatternResolver;
   39   import org.springframework.core.io.support.ResourcePatternUtils;
   40   
   41   /**
   42    * <p>Keyed-singleton implementation of {@link BeanFactoryLocator},
   43    * which accesses shared Spring {@link BeanFactory} instances.</p>
   44    *
   45    * <p>Please see the warning in BeanFactoryLocator's javadoc about appropriate usage
   46    * of singleton style BeanFactoryLocator implementations. It is the opinion of the 
   47    * Spring team that the use of this class and similar classes is unnecessary except
   48    * (sometimes) for a small amount of glue code. Excessive usage will lead to code
   49    * that is more tightly coupled, and harder to modify or test.</p>
   50    *
   51    * <p>In this implementation, a BeanFactory is built up from one or more XML
   52    * definition file fragments, accessed as resources. The default resource name
   53    * searched for is 'classpath*:beanRefFactory.xml', with the Spring-standard
   54    * 'classpath*:' prefix ensuring that if the classpath contains multiple copies
   55    * of this file (perhaps one in each component jar) they will be combined. To
   56    * override the default resource name, instead of using the no-arg 
   57    * {@link #getInstance()} method, use the {@link #getInstance(String selector)}
   58    * variant, which will treat the 'selector' argument as the resource name to
   59    * search for.</p>
   60    * 
   61    * <p>The purpose of this 'outer' BeanFactory is to create and hold a copy of one
   62    * or more 'inner' BeanFactory or ApplicationContext instances, and allow those
   63    * to be obtained either directly or via an alias. As such, this class provides
   64    * both singleton style access to one or more BeanFactories/ApplicationContexts,
   65    * and also a level of indirection, allowing multiple pieces of code, which are
   66    * not able to work in a Dependency Injection fashion, to refer to and use the
   67    * same target BeanFactory/ApplicationContext instance(s), by different names.<p>
   68    *
   69    * <p>Consider an example application scenario:
   70    *
   71    * <ul>
   72    * <li><code>com.mycompany.myapp.util.applicationContext.xml</code> -
   73    * ApplicationContext definition file which defines beans for 'util' layer.
   74    * <li><code>com.mycompany.myapp.dataaccess-applicationContext.xml</code> -
   75    * ApplicationContext definition file which defines beans for 'data access' layer.
   76    * Depends on the above.
   77    * <li><code>com.mycompany.myapp.services.applicationContext.xml</code> -
   78    * ApplicationContext definition file which defines beans for 'services' layer.
   79    * Depends on the above.
   80    * </ul>
   81    *
   82    * <p>In an ideal scenario, these would be combined to create one ApplicationContext,
   83    * or created as three hierarchical ApplicationContexts, by one piece of code
   84    * somewhere at application startup (perhaps a Servlet filter), from which all other
   85    * code in the application would flow, obtained as beans from the context(s). However
   86    * when third party code enters into the picture, things can get problematic. If the 
   87    * third party code needs to create user classes, which should normally be obtained
   88    * from a Spring BeanFactory/ApplicationContext, but can handle only newInstance()
   89    * style object creation, then some extra work is required to actually access and 
   90    * use object from a BeanFactory/ApplicationContext. One solutions is to make the
   91    * class created by the third party code be just a stub or proxy, which gets the
   92    * real object from a BeanFactory/ApplicationContext, and delegates to it. However,
   93    * it is is not normally workable for the stub to create the BeanFactory on each
   94    * use, as depending on what is inside it, that can be an expensive operation.
   95    * Additionally, there is a fairly tight coupling between the stub and the name of
   96    * the definition resource for the BeanFactory/ApplicationContext. This is where
   97    * SingletonBeanFactoryLocator comes in. The stub can obtain a
   98    * SingletonBeanFactoryLocator instance, which is effectively a singleton, and
   99    * ask it for an appropriate BeanFactory. A subsequent invocation (assuming the
  100    * same class loader is involved) by the stub or another piece of code, will obtain
  101    * the same instance. The simple aliasing mechanism allows the context to be asked
  102    * for by a name which is appropriate for (or describes) the user. The deployer can
  103    * match alias names to actual context names.
  104    *
  105    * <p>Another use of SingletonBeanFactoryLocator, is to demand-load/use one or more
  106    * BeanFactories/ApplicationContexts. Because the definition can contain one of more
  107    * BeanFactories/ApplicationContexts, which can be independent or in a hierarchy, if 
  108    * they are set to lazy-initialize, they will only be created when actually requested
  109    * for use.
  110    *
  111    * <p>Given the above-mentioned three ApplicationContexts, consider the simplest
  112    * SingletonBeanFactoryLocator usage scenario, where there is only one single
  113    * <code>beanRefFactory.xml</code> definition file:
  114    *
  115    * <pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?>
  116    * &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
  117    * 
  118    * &lt;beans>
  119    * 
  120    *   &lt;bean id="com.mycompany.myapp"
  121    *         class="org.springframework.context.support.ClassPathXmlApplicationContext">
  122    *     &lt;constructor-arg>
  123    *       &lt;list>
  124    *         &lt;value>com/mycompany/myapp/util/applicationContext.xml&lt;/value>
  125    *         &lt;value>com/mycompany/myapp/dataaccess/applicationContext.xml&lt;/value>
  126    *         &lt;value>com/mycompany/myapp/dataaccess/services.xml&lt;/value>
  127    *       &lt;/list>
  128    *     &lt;/constructor-arg>
  129    *   &lt;/bean>
  130    * 
  131    * &lt;/beans>
  132    * </pre>
  133    *
  134    * The client code is as simple as:
  135    *
  136    * <pre class="code">
  137    * BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
  138    * BeanFactoryReference bf = bfl.useBeanFactory("com.mycompany.myapp");
  139    * // now use some bean from factory 
  140    * MyClass zed = bf.getFactory().getBean("mybean");
  141    * </pre>
  142    *
  143    * Another relatively simple variation of the <code>beanRefFactory.xml</code> definition file could be:
  144    *
  145    * <pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?>
  146    * &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
  147    * 
  148    * &lt;beans>
  149    * 
  150    *   &lt;bean id="com.mycompany.myapp.util" lazy-init="true"
  151    *         class="org.springframework.context.support.ClassPathXmlApplicationContext">
  152    *     &lt;constructor-arg>
  153    *       &lt;value>com/mycompany/myapp/util/applicationContext.xml&lt;/value>
  154    *     &lt;/constructor-arg>
  155    *   &lt;/bean>
  156    * 
  157    *   &lt;!-- child of above -->
  158    *   &lt;bean id="com.mycompany.myapp.dataaccess" lazy-init="true"
  159    *         class="org.springframework.context.support.ClassPathXmlApplicationContext">
  160    *     &lt;constructor-arg>
  161    *       &lt;list>&lt;value>com/mycompany/myapp/dataaccess/applicationContext.xml&lt;/value>&lt;/list>
  162    *     &lt;/constructor-arg>
  163    *     &lt;constructor-arg>
  164    *       &lt;ref bean="com.mycompany.myapp.util"/>
  165    *     &lt;/constructor-arg>
  166    *   &lt;/bean>
  167    * 
  168    *   &lt;!-- child of above -->
  169    *   &lt;bean id="com.mycompany.myapp.services" lazy-init="true"
  170    *         class="org.springframework.context.support.ClassPathXmlApplicationContext">
  171    *     &lt;constructor-arg>
  172    *       &lt;list>&lt;value>com/mycompany/myapp/dataaccess.services.xml&lt;/value>&lt;/value>
  173    *     &lt;/constructor-arg>
  174    *     &lt;constructor-arg>
  175    *       &lt;ref bean="com.mycompany.myapp.dataaccess"/>
  176    *     &lt;/constructor-arg>
  177    *   &lt;/bean>
  178    * 
  179    *   &lt;!-- define an alias -->
  180    *   &lt;bean id="com.mycompany.myapp.mypackage"
  181    *         class="java.lang.String">
  182    *     &lt;constructor-arg>
  183    *       &lt;value>com.mycompany.myapp.services&lt;/value>
  184    *     &lt;/constructor-arg>
  185    *   &lt;/bean>
  186    * 
  187    * &lt;/beans>
  188    * </pre>
  189    *
  190    * <p>In this example, there is a hierarchy of three contexts created. The (potential)
  191    * advantage is that if the lazy flag is set to true, a context will only be created
  192    * if it's actually used. If there is some code that is only needed some of the time,
  193    * this mechanism can save some resources. Additionally, an alias to the last context
  194    * has been created. Aliases allow usage of the idiom where client code asks for a
  195    * context with an id which represents the package or module the code is in, and the
  196    * actual definition file(s) for the SingletonBeanFactoryLocator maps that id to
  197    * a real context id.
  198    *
  199    * <p>A final example is more complex, with a <code>beanRefFactory.xml</code> for every module.
  200    * All the files are automatically combined to create the final definition.
  201    *
  202    * <p><code>beanRefFactory.xml</code> file inside jar for util module:
  203    *
  204    * <pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?>
  205    * &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
  206    * 
  207    * &lt;beans>
  208    *   &lt;bean id="com.mycompany.myapp.util" lazy-init="true"
  209    *        class="org.springframework.context.support.ClassPathXmlApplicationContext">
  210    *     &lt;constructor-arg>
  211    *       &lt;value>com/mycompany/myapp/util/applicationContext.xml&lt;/value>
  212    *     &lt;/constructor-arg>
  213    *   &lt;/bean>
  214    * &lt;/beans>
  215    * </pre>
  216    * 
  217    * <code>beanRefFactory.xml</code> file inside jar for data-access module:<br>
  218    *
  219    * <pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?>
  220    * &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
  221    * 
  222    * &lt;beans>
  223    *   &lt;!-- child of util -->
  224    *   &lt;bean id="com.mycompany.myapp.dataaccess" lazy-init="true"
  225    *        class="org.springframework.context.support.ClassPathXmlApplicationContext">
  226    *     &lt;constructor-arg>
  227    *       &lt;list>&lt;value>com/mycompany/myapp/dataaccess/applicationContext.xml&lt;/value>&lt;/list>
  228    *     &lt;/constructor-arg>
  229    *     &lt;constructor-arg>
  230    *       &lt;ref bean="com.mycompany.myapp.util"/>
  231    *     &lt;/constructor-arg>
  232    *   &lt;/bean>
  233    * &lt;/beans>
  234    * </pre>
  235    * 
  236    * <code>beanRefFactory.xml</code> file inside jar for services module:
  237    *
  238    * <pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?>
  239    * &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
  240    * 
  241    * &lt;beans>
  242    *   &lt;!-- child of data-access -->
  243    *   &lt;bean id="com.mycompany.myapp.services" lazy-init="true"
  244    *        class="org.springframework.context.support.ClassPathXmlApplicationContext">
  245    *     &lt;constructor-arg>
  246    *       &lt;list>&lt;value>com/mycompany/myapp/dataaccess/services.xml&lt;/value>&lt;/list>
  247    *     &lt;/constructor-arg>
  248    *     &lt;constructor-arg>
  249    *       &lt;ref bean="com.mycompany.myapp.dataaccess"/>
  250    *     &lt;/constructor-arg>
  251    *   &lt;/bean>
  252    * &lt;/beans>
  253    * </pre>
  254    * 
  255    * <code>beanRefFactory.xml</code> file inside jar for mypackage module. This doesn't
  256    * create any of its own contexts, but allows the other ones to be referred to be
  257    * a name known to this module:
  258    *
  259    * <pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?>
  260    * &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
  261    * 
  262    * &lt;beans>
  263    *   &lt;!-- define an alias for "com.mycompany.myapp.services" -->
  264    *   &lt;alias name="com.mycompany.myapp.services" alias="com.mycompany.myapp.mypackage"/&gt;
  265    * &lt;/beans>
  266    * </pre>
  267    *   
  268    * @author Colin Sampaleanu
  269    * @author Juergen Hoeller
  270    * @see org.springframework.context.access.ContextSingletonBeanFactoryLocator
  271    * @see org.springframework.context.access.DefaultLocatorFactory
  272    */
  273   public class SingletonBeanFactoryLocator implements BeanFactoryLocator {
  274   
  275   	private static final String DEFAULT_RESOURCE_LOCATION = "classpath*:beanRefFactory.xml";
  276   
  277   	protected static final Log logger = LogFactory.getLog(SingletonBeanFactoryLocator.class);
  278   
  279   	/** The keyed BeanFactory instances */
  280   	private static Map instances = new HashMap();
  281   
  282   
  283   	/**
  284   	 * Returns an instance which uses the default "classpath*:beanRefFactory.xml",
  285   	 * as the name of the definition file(s). All resources returned by calling the
  286   	 * current thread context ClassLoader's <code>getResources</code> method with
  287   	 * this name will be combined to create a BeanFactory definition set.
  288   	 * @return the corresponding BeanFactoryLocator instance
  289   	 * @throws BeansException in case of factory loading failure
  290   	 */
  291   	public static BeanFactoryLocator getInstance() throws BeansException {
  292   		return getInstance(null);
  293   	}
  294   
  295   	/**
  296   	 * Returns an instance which uses the the specified selector, as the name of the
  297   	 * definition file(s). In the case of a name with a Spring 'classpath*:' prefix,
  298   	 * or with no prefix, which is treated the same, the current thread context
  299   	 * ClassLoader's <code>getResources</code> method will be called with this value
  300   	 * to get all resources having that name. These resources will then be combined to
  301   	 * form a definition. In the case where the name uses a Spring 'classpath:' prefix,
  302   	 * or a standard URL prefix, then only one resource file will be loaded as the
  303   	 * definition.
  304   	 * @param selector the name of the resource(s) which will be read and
  305   	 * combined to form the definition for the BeanFactoryLocator instance.
  306   	 * Any such files must form a valid BeanFactory definition.
  307   	 * @return the corresponding BeanFactoryLocator instance
  308   	 * @throws BeansException in case of factory loading failure
  309   	 */
  310   	public static BeanFactoryLocator getInstance(String selector) throws BeansException {
  311   		String resourceLocation = selector;
  312   		if (resourceLocation == null) {
  313   			resourceLocation = DEFAULT_RESOURCE_LOCATION;
  314   		}
  315   
  316   		// For backwards compatibility, we prepend 'classpath*:' to the selector name if there
  317   		// is no other prefix (i.e. classpath*:, classpath:, or some URL prefix.
  318   		if (!ResourcePatternUtils.isUrl(resourceLocation)) {
  319   			resourceLocation = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resourceLocation;
  320   		}
  321   
  322   		synchronized (instances) {
  323   			if (logger.isTraceEnabled()) {
  324   				logger.trace("SingletonBeanFactoryLocator.getInstance(): instances.hashCode=" +
  325   						instances.hashCode() + ", instances=" + instances);
  326   			}
  327   			BeanFactoryLocator bfl = (BeanFactoryLocator) instances.get(resourceLocation);
  328   			if (bfl == null) {
  329   				bfl = new SingletonBeanFactoryLocator(resourceLocation);
  330   				instances.put(resourceLocation, bfl);
  331   			}
  332   			return bfl;
  333   		}
  334   	}
  335   
  336   
  337   	// We map BeanFactoryGroup objects by String keys, and by the definition object.
  338   	private final Map bfgInstancesByKey = new HashMap();
  339   
  340   	private final Map bfgInstancesByObj = new HashMap();
  341   
  342   	private final String resourceLocation;
  343   
  344   
  345   	/**
  346   	 * Constructor which uses the the specified name as the resource name
  347   	 * of the definition file(s).
  348   	 * @param resourceLocation the Spring resource location to use
  349   	 * (either a URL or a "classpath:" / "classpath*:" pseudo URL)
  350   	 */
  351   	protected SingletonBeanFactoryLocator(String resourceLocation) {
  352   		this.resourceLocation = resourceLocation;
  353   	}
  354   
  355   	public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
  356   		synchronized (this.bfgInstancesByKey) {
  357   			BeanFactoryGroup bfg = (BeanFactoryGroup) this.bfgInstancesByKey.get(this.resourceLocation);
  358   
  359   			if (bfg != null) {
  360   				bfg.refCount++;
  361   			}
  362   			else {
  363   				// This group definition doesn't exist, we need to try to load it.
  364   				if (logger.isTraceEnabled()) {
  365   					logger.trace("Factory group with resource name [" + this.resourceLocation +
  366   							"] requested. Creating new instance.");
  367   				}
  368   				
  369   				// Create the BeanFactory but don't initialize it.
  370   				BeanFactory groupContext = createDefinition(this.resourceLocation, factoryKey);
  371   
  372   				// Record its existence now, before instantiating any singletons.
  373   				bfg = new BeanFactoryGroup();
  374   				bfg.definition = groupContext;
  375   				bfg.refCount = 1;
  376   				this.bfgInstancesByKey.put(this.resourceLocation, bfg);
  377   				this.bfgInstancesByObj.put(groupContext, bfg);
  378   
  379   				// Now initialize the BeanFactory. This may cause a re-entrant invocation
  380   				// of this method, but since we've already added the BeanFactory to our
  381   				// mappings, the next time it will be found and simply have its
  382   				// reference count incremented.
  383   				try {
  384   					initializeDefinition(groupContext);
  385   				}
  386   				catch (BeansException ex) {
  387   					this.bfgInstancesByKey.remove(this.resourceLocation);
  388   					this.bfgInstancesByObj.remove(groupContext);
  389   					throw new BootstrapException("Unable to initialize group definition. " +
  390   						"Group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]", ex);
  391   				}
  392   			}
  393   
  394   			try {
  395   				BeanFactory beanFactory = null;
  396   				if (factoryKey != null) {
  397   					beanFactory = (BeanFactory) bfg.definition.getBean(factoryKey, BeanFactory.class);
  398   				}
  399   				else if (bfg.definition instanceof ListableBeanFactory) {
  400   					beanFactory = (BeanFactory)
  401   							BeanFactoryUtils.beanOfType((ListableBeanFactory) bfg.definition, BeanFactory.class);
  402   				}
  403   				else {
  404   					throw new IllegalStateException(
  405   							"Factory key is null, and underlying factory is not a ListableBeanFactory: " + bfg.definition);
  406   				}
  407   				return new CountingBeanFactoryReference(beanFactory, bfg.definition);
  408   			}
  409   			catch (BeansException ex) {
  410   				throw new BootstrapException("Unable to return specified BeanFactory instance: factory key [" +
  411   						factoryKey + "], from group with resource name [" + this.resourceLocation + "]", ex);
  412   			}
  413   
  414   		}
  415   	}
  416   
  417   	/**
  418   	 * Actually creates definition in the form of a BeanFactory, given a resource name
  419   	 * which supports standard Spring resource prefixes ('classpath:', 'classpath*:', etc.)
  420   	 * This is split out as a separate method so that subclasses can override the actual
  421   	 * type used (to be an ApplicationContext, for example).
  422   	 * <p>The default implementation simply builds a
  423   	 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
  424   	 * and populates it using an
  425   	 * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
  426   	 * <p>This method should not instantiate any singletons. That function is performed
  427   	 * by {@link #initializeDefinition initializeDefinition()}, which should also be
  428   	 * overridden if this method is.
  429   	 * @param resourceLocation the resource location for this factory group
  430   	 * @param factoryKey the bean name of the factory to obtain
  431   	 * @return the corresponding BeanFactory reference
  432   	 */
  433   	protected BeanFactory createDefinition(String resourceLocation, String factoryKey) {
  434   		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
  435   		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
  436   		ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
  437   
  438   		try {
  439   			Resource[] configResources = resourcePatternResolver.getResources(resourceLocation);
  440   			if (configResources.length == 0) {
  441   				throw new FatalBeanException("Unable to find resource for specified definition. " +
  442   						"Group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]");
  443   			}
  444   			reader.loadBeanDefinitions(configResources);
  445   		}
  446   		catch (IOException ex) {
  447   			throw new BeanDefinitionStoreException(
  448   					"Error accessing bean definition resource [" + this.resourceLocation + "]", ex);
  449   		}
  450   		catch (BeanDefinitionStoreException ex) {
  451   			throw new FatalBeanException("Unable to load group definition: " +
  452   					"group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]", ex);
  453   		}
  454   
  455   		return factory;
  456   	}
  457   	
  458   	/**
  459   	 * Instantiate singletons and do any other normal initialization of the factory.
  460   	 * Subclasses that override {@link #createDefinition createDefinition()} should
  461   	 * also override this method.
  462   	 * @param groupDef the factory returned by {@link #createDefinition createDefinition()}
  463   	 */
  464   	protected void initializeDefinition(BeanFactory groupDef) {
  465   		if (groupDef instanceof ConfigurableListableBeanFactory) {
  466   			((ConfigurableListableBeanFactory) groupDef).preInstantiateSingletons();
  467   		}
  468   	}
  469   
  470   	/**
  471   	 * Destroy definition in separate method so subclass may work with other definition types.
  472   	 * @param groupDef the factory returned by {@link #createDefinition createDefinition()}
  473   	 * @param selector the resource location for this factory group
  474   	 */
  475   	protected void destroyDefinition(BeanFactory groupDef, String selector) {
  476   		if (groupDef instanceof ConfigurableBeanFactory) {
  477   			if (logger.isTraceEnabled()) {
  478   				logger.trace("Factory group with selector '" + selector +
  479   						"' being released, as there are no more references to it");
  480   			}
  481   			((ConfigurableBeanFactory) groupDef).destroySingletons();
  482   		}
  483   	}
  484   
  485   
  486   	/**
  487   	 * We track BeanFactory instances with this class.
  488   	 */
  489   	private static class BeanFactoryGroup {
  490   
  491   		private BeanFactory definition;
  492   
  493   		private int refCount = 0;
  494   	}
  495   
  496   
  497   	/**
  498   	 * BeanFactoryReference implementation for this locator.
  499   	 */
  500   	private class CountingBeanFactoryReference implements BeanFactoryReference {
  501   
  502   		private BeanFactory beanFactory;
  503   
  504   		private BeanFactory groupContextRef;
  505   
  506   		public CountingBeanFactoryReference(BeanFactory beanFactory, BeanFactory groupContext) {
  507   			this.beanFactory = beanFactory;
  508   			this.groupContextRef = groupContext;
  509   		}
  510   
  511   		public BeanFactory getFactory() {
  512   			return this.beanFactory;
  513   		}
  514   
  515   		// Note that it's legal to call release more than once!
  516   		public void release() throws FatalBeanException {
  517   			synchronized (bfgInstancesByKey) {
  518   				BeanFactory savedRef = this.groupContextRef;
  519   				if (savedRef != null) {
  520   					this.groupContextRef = null;
  521   					BeanFactoryGroup bfg = (BeanFactoryGroup) bfgInstancesByObj.get(savedRef);
  522   					if (bfg != null) {
  523   						bfg.refCount--;
  524   						if (bfg.refCount == 0) {
  525   							destroyDefinition(savedRef, resourceLocation);
  526   							bfgInstancesByKey.remove(resourceLocation);
  527   							bfgInstancesByObj.remove(savedRef);
  528   						}
  529   					}
  530   					else {
  531   						// This should be impossible.
  532   						logger.warn("Tried to release a SingletonBeanFactoryLocator group definition " +
  533   								"more times than it has actually been used. Resource name [" + resourceLocation + "]");
  534   					}
  535   				}
  536   			}
  537   		}
  538   	}
  539   
  540   }

Home » Spring-Framework-090522 » org.springframework » beans » factory » access » [javadoc | source]