📄 singletonbeanfactorylocator.java
字号:
*/
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 + -