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

📄 singletonbeanfactorylocator.java

📁 spring的源代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
 */
public class SingletonBeanFactoryLocator implements BeanFactoryLocator {

	public static final String BEANS_REFS_XML_NAME = "beanRefFactory.xml";

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

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


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

	private Map bfgInstancesByObj = new HashMap();

	private String resourceName;


	/**
	 * Returns an instance which uses the default "beanRefFactory.xml", as the name of the
	 * definition file(s). All resources returned by 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). All resources returned by the current thread's context
	 * classloader's getResources() method with this name will be combined to create a
	 * definition, which is just a a BeanFactory.
	 * @param selector the name of the resource(s) which will be read and combine to
	 * form the definition for the SingletonBeanFactoryLocator instance
	 */
	public static BeanFactoryLocator getInstance(String selector) throws FatalBeanException {
		synchronized (instances) {
			// debugging trace only
			//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;
		}
	}


	/**
	 * 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;
	}

	// see superclass JavaDoc: org.springframework.beans.factory.access.BeanFactoryLocator#useFactory(java.lang.String)
	public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
		synchronized (this.bfgInstancesByKey) {
			BeanFactoryGroup bfg = (BeanFactoryGroup) this.bfgInstancesByKey
					.get(this.resourceName);

			if (bfg != null) {
				// debugging trace only
				//if (logger.isDebugEnabled()) {
				//	logger.debug("Factory group with resourceName '" + this.resourceName
				//			+ "' requested. Using existing instance.");
				//}
				bfg.refCount++;
			}
			else {
				// this group definition doesn't exist, we need to try to load it
				if (logger.isDebugEnabled()) {
					logger.debug("Factory group with resourceName '" + this.resourceName
							+ "' requested. Creating new instance.");
				}

				Collection resourceUrls;
				try {
					resourceUrls = getAllDefinitionResources(this.resourceName);
				}
				catch (IOException ex) {
					throw new FatalBeanException(
							"Unable to load group definition. Group resource name:"
									+ this.resourceName + ", factoryKey:" + factoryKey,
							ex);
				}

				int numResources = resourceUrls.size();
				if (numResources == 0)
					throw new FatalBeanException(
							"Unable to find definition for specified definition. Group:"
									+ this.resourceName + ", contextId:" + factoryKey);

				String[] resources = new String[numResources];
				Iterator it = resourceUrls.iterator();
				for (int i = 0; i < numResources; ++i) {
					URL url = (URL) it.next();
					resources[i] = url.toExternalForm();
				}

				BeanFactory groupContext = createDefinition(resources);

				bfg = new BeanFactoryGroup();
				bfg.definition = groupContext;
				bfg.resourceName = this.resourceName;
				bfg.refCount = 1;
				this.bfgInstancesByKey.put(this.resourceName, bfg);
				this.bfgInstancesByObj.put(groupContext, bfg);
			}

			final BeanFactory groupContext = bfg.definition;

			String lookupId = factoryKey;
			Object bean;
			try {
				bean = groupContext.getBean(lookupId);
			}
			catch (BeansException e) {
				throw new FatalBeanException(
						"Unable to return specified BeanFactory instance: factoryKey="
								+ factoryKey + ", from group with resourceName: "
								+ this.resourceName, e);
			}

			if (bean instanceof String) {
				// we have some indirection
				lookupId = (String) bean;
				try {
					bean = groupContext.getBean(lookupId);
				}
				catch (BeansException e) {
					throw new FatalBeanException(
							"Unable to return specified BeanFactory instance: lookupId="
									+ lookupId + ", factoryKey=" + factoryKey
									+ ", from group with resourceName: "
									+ this.resourceName, e);
				}
			}

			if (!(bean instanceof BeanFactory))
				throw new FatalBeanException(
						"Returned bean is not BeanFactory or its subclass. lookupId="
								+ lookupId + ", factoryKey=" + factoryKey
								+ ", from group with resourceName: " + this.resourceName
								+ ". Returned cbject class is: " + bean.getClass());

			final BeanFactory beanFactory = (BeanFactory) bean;

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

				public void release() throws FatalBeanException {
					synchronized (bfgInstancesByKey) {
						BeanFactoryGroup bfg = (BeanFactoryGroup) bfgInstancesByObj.get(this.groupContextRef);
						if (bfg != null) {
							bfg.refCount--;
							if (bfg.refCount == 0) {
								destroyDefinition(this.groupContextRef, resourceName);
								bfgInstancesByKey.remove(resourceName);
								bfgInstancesByObj.remove(this.groupContextRef);
							}
						}
						else {
							logger.warn("Tried to release a SingletonBeanFactoryLocator (or subclass) group definition " +
													"more times than it has actually been used. resourceName='" + resourceName + "'");
						}
					}
				}
			};
		}
	}

	/**
	 * Actually creates definition in the form of a BeanFactory, given an array of URLs
	 * representing resources which should be combined. This is split out as a separate
	 * method so that subclasses can override the actual type uses (to be an
	 * ApplicationContext, for example).
	 */
	protected BeanFactory createDefinition(String[] resources) throws BeansException {
		DefaultListableBeanFactory fac = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(fac);
		for (int i = 0; i < resources.length; ++i) {
			try {
				reader.loadBeanDefinitions(new UrlResource(resources[i]));
			}
			catch (MalformedURLException ex) {
				throw new BeanDefinitionStoreException("Bad URL when loading definition", ex);
			}
		}
		fac.preInstantiateSingletons();
		return fac;
	}
	
    /**
     * 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 resourceName '"
						+ resourceName
						+ "' being released, as no more references.");
			}
			((ConfigurableBeanFactory) groupDef).destroySingletons();
		}
	}

	/**
	 * Method which returns resources (as URLs) which make up the definition of one
	 * bean factory/application context.
	 * <p>Protected so that test cases may subclass this class and override this
	 * method to avoid the need for multiple classloaders to test multi-file
	 * capability in the rest of the class.
	 */
	protected Collection getAllDefinitionResources(String resourceName) throws IOException {
		ClassLoader cl = Thread.currentThread().getContextClassLoader();
		// don't depend on JDK 1.4, do our own conversion
		Enumeration resourceEnum = cl.getResources(resourceName);
		Collection list = new ArrayList();
		while (resourceEnum.hasMoreElements()) {
			list.add(resourceEnum.nextElement());
		}
		return list;
	}


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

		private BeanFactory definition;

		private String resourceName;

		private int refCount = 0;
	}

}

⌨️ 快捷键说明

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