⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 singletonbeanfactorylocator.java

📁 spring的源代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
 *   <!-- define an alias for "com.mycompany.myapp.services" -->
 *   <alias name="com.mycompany.myapp.services" alias="com.mycompany.myapp.mypackage"/>
 * </beans>
 * </pre>
 *   
 * @author Colin Sampaleanu
 * @see org.springframework.context.access.DefaultLocatorFactory
 */
public class SingletonBeanFactoryLocator implements BeanFactoryLocator {

	private static final String BEANS_REFS_XML_NAME = "classpath*:beanRefFactory.xml";

	protected static final Log logger = LogFactory.getLog(SingletonBeanFactoryLocator.class);

	// the keyed singleton instances
	private static Map instances = new HashMap();


	/**
	 * Returns an instance which uses the default "classpath*:beanRefFactory.xml",
	 * as the name of the definition file(s). All resources returned by calling the
	 * current thread's context classloader's getResources() method with this name
	 * will be combined to create a definition, which is just a BeanFactory.
	 */
	public static BeanFactoryLocator getInstance() throws FatalBeanException {
		return getInstance(BEANS_REFS_XML_NAME);
	}

	/**
	 * Returns an instance which uses the the specified selector, as the name of the
	 * definition file(s). In the case of a name with a Spring 'classpath*:' prefix,
	 * or with no prefix, which is treated the same, the current thread's context
	 * classloader's getResources() method will be called with this value to get all
	 * resources having that name. These resources will then be combined to form a
	 * definition. In the case where the name uses a Spring 'classpath:' prefix, or
	 * a standard URL prefix, then only one resource file will be loaded as the
	 * definition.
	 * @param selector the name of the resource(s) which will be read and combine to
	 * form the definition for the SingletonBeanFactoryLocator instance. The one file
	 * or multiple fragments with this name must form a valid BeanFactory definition.
	 */
	public static BeanFactoryLocator getInstance(String selector) throws FatalBeanException {
		// For backwards compatibility, we prepend 'classpath*:' to the selector name if there
		// is no other prefix (i.e. classpath*:, classpath:, or some URL prefix.
		if (selector.indexOf(':') == -1) {
			selector = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + selector;
		}

		synchronized (instances) {
			if (logger.isDebugEnabled()) {
				logger.debug("SingletonBeanFactoryLocator.getInstance(): instances.hashCode=" +
						instances.hashCode() + ", instances=" + instances);
			}
			BeanFactoryLocator bfl = (BeanFactoryLocator) instances.get(selector);
			if (bfl == null) {
				bfl = new SingletonBeanFactoryLocator(selector);
				instances.put(selector, bfl);
			}
			return bfl;
		}
	}


	// We map BeanFactoryGroup objects by String keys, and by the definition object.
	private final Map bfgInstancesByKey = new HashMap();

	private final Map bfgInstancesByObj = new HashMap();

	private final String resourceName;


	/**
	 * Constructor which uses the default "beanRefFactory.xml", as the name of the
	 * definition file(s). All resources returned by the definition classloader's
	 * getResources() method with this name will be combined to create a definition.
	 */
	protected SingletonBeanFactoryLocator() {
		this.resourceName = BEANS_REFS_XML_NAME;
	}

	/**
	 * Constructor which uses the the specified name as the name of the
	 * definition file(s). All resources returned by the definition classloader's
	 * getResources() method with this name will be combined to create a definition
	 * definition.
	 */
	protected SingletonBeanFactoryLocator(String resourceName) {
		this.resourceName = resourceName;
	}

	public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
		synchronized (this.bfgInstancesByKey) {
			BeanFactoryGroup bfg = (BeanFactoryGroup) this.bfgInstancesByKey.get(this.resourceName);

			if (bfg != null) {
				bfg.refCount++;
			}
			else {
				// This group definition doesn't exist, we need to try to load it.
				if (logger.isDebugEnabled()) {
					logger.debug("Factory group with resource name [" + this.resourceName +
							"] requested. Creating new instance.");
				}
				
				// Create the BeanFactory but don't initialize it.
				BeanFactory groupContext = createDefinition(this.resourceName, factoryKey);

				// Record its existence now, before instantiating any singletons.
				bfg = new BeanFactoryGroup();
				bfg.definition = groupContext;
				bfg.refCount = 1;
				this.bfgInstancesByKey.put(this.resourceName, bfg);
				this.bfgInstancesByObj.put(groupContext, bfg);

				// Now initialize the BeanFactory. This may cause a re-entrant invocation
				// of this method, but since we've already added the BeanFactory to our
				// mappings, the next time it will be found and simply have its
				// reference count incremented.
				try {
					initializeDefinition(groupContext);
				}
				catch (BeansException ex) {
					throw new BootstrapException("Unable to initialize group definition. " +
						"Group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]", ex);
				}
			}

			final BeanFactory groupContext = bfg.definition;

			String beanName = factoryKey;
			Object bean;
			try {
				bean = groupContext.getBean(beanName);
				if (bean instanceof String) {
					logger.warn("You're using the deprecated alias-through-String-bean feature, " +
							"which will be removed as of Spring 2.0. It is recommended to replace this " +
							"with an <alias> tag (see SingletonBeanFactoryLocator javadoc).");
					beanName = (String) bean;
					bean = groupContext.getBean(beanName);
				}
			}
			catch (BeansException ex) {
				throw new BootstrapException("Unable to return specified BeanFactory instance: factory key [" +
						factoryKey + "], from group with resource name [" + this.resourceName + "]", ex);
			}

			if (!(bean instanceof BeanFactory)) {
				throw new BootstrapException("Bean '" + beanName + "' is not a BeanFactory: factory key [" +
						factoryKey + "], from group with resource name [" + this.resourceName + "]");
			}

			final BeanFactory beanFactory = (BeanFactory) bean;

			return new BeanFactoryReference() {
				
				BeanFactory groupContextRef;
				
				// constructor
				{
					this.groupContextRef = groupContext;
				}
				
				public BeanFactory getFactory() {
					return beanFactory;
				}

				// Note that it's legal to call release more than once!
				public void release() throws FatalBeanException {
					synchronized (bfgInstancesByKey) {
						BeanFactory savedRef = this.groupContextRef;
						if (savedRef != null) {
							this.groupContextRef = null;
							BeanFactoryGroup bfg = (BeanFactoryGroup) bfgInstancesByObj.get(savedRef);
							if (bfg != null) {
								bfg.refCount--;
								if (bfg.refCount == 0) {
									destroyDefinition(savedRef, resourceName);
									bfgInstancesByKey.remove(resourceName);
									bfgInstancesByObj.remove(savedRef);
								}
							}
							else {
								// This should be impossible.
								logger.warn("Tried to release a SingletonBeanFactoryLocator group definition " +
										"more times than it has actually been used. Resource name [" + resourceName + "]");
							}
						}
					}
				}
			};
		}
	}

	/**
	 * Actually creates definition in the form of a BeanFactory, given a resource name
	 * which supports standard Spring Resource prefixes ('classpath:', 'classpath*:', etc.)
	 * This is split out as a separate method so that subclasses can override the actual
	 * type used (to be an ApplicationContext, for example).
	 * <p>This method should not instantiate any singletons. That function is performed
	 * by {@link #initializeDefinition initializeDefinition()}, which should also be
	 * overridden if this method is.
	 */
	protected BeanFactory createDefinition(String resourceName, String factoryKey) throws BeansException {
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
		ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

		try {
			Resource[] configResources = resourcePatternResolver.getResources(resourceName);
			if (configResources.length == 0) {
				throw new FatalBeanException("Unable to find resource for specified definition. " +
						"Group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]");
			}
			reader.loadBeanDefinitions(configResources);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"Error accessing bean definition resource [" + this.resourceName + "]", ex);
		}
		catch (BeanDefinitionStoreException ex) {
			throw new FatalBeanException("Unable to load group definition: " +
					"group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]", ex);
		}

		return factory;
	}
	
	/**
	 * Instantiate singletons and do any other normal initialization of the factory.
	 * Subclasses that override {@link #createDefinition createDefinition()} should
	 * also override this method.
	 * @param groupDef the factory returned by {@link #createDefinition createDefinition()}
	 */
	protected void initializeDefinition(BeanFactory groupDef) throws BeansException {
		if (groupDef instanceof ConfigurableListableBeanFactory) {
			((ConfigurableListableBeanFactory) groupDef).preInstantiateSingletons();
		}
	}

	/**
	 * Destroy definition in separate method so subclass may work with other definition types.
	 */
	protected void destroyDefinition(BeanFactory groupDef, String resourceName) throws BeansException {
		if (groupDef instanceof ConfigurableBeanFactory) {
			// debugging trace only
			if (logger.isDebugEnabled()) {
				logger.debug("Factory group with resource name '" + resourceName +
						"' being released, as there are no more references to it.");
			}
			((ConfigurableBeanFactory) groupDef).destroySingletons();
		}
	}


	/**
	 * We track BeanFactory instances with this class.
	 */
	private static class BeanFactoryGroup {

		private BeanFactory definition;

		private int refCount = 0;
	}

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -