📄 singletonbeanfactorylocator.java
字号:
* <bean id="com.mycompany.myapp.mypackage"
* class="java.lang.String">
* <constructor-arg>
* <value>com.mycompany.myapp.services</value>
* </constructor-arg>
* </bean>
*
* </beans>
* </pre>
*
* @author Colin Sampaleanu
* @see org.springframework.context.access.DefaultLocatorFactory
*/
public class SingletonBeanFactoryLocator implements BeanFactoryLocator {
public 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();
// 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 "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);
}
/**
* <p>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.</p>
*
* @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_URL_PREFIX + selector;
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;
}
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 resource name [" + this.resourceName
+ "] requested. Creating new instance.");
}
BeanFactory groupContext = createDefinition(this.resourceName, factoryKey);
bfg = new BeanFactoryGroup();
bfg.definition = groupContext;
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 ex) {
throw new FatalBeanException("Unable to return specified BeanFactory instance: factory key [" +
factoryKey + "], from group with resource name [" + this.resourceName + "]", ex);
}
if (bean instanceof String) {
// we have some indirection
lookupId = (String) bean;
try {
bean = groupContext.getBean(lookupId);
}
catch (BeansException ex) {
throw new FatalBeanException("Unable to return specified BeanFactory instance: lookup ID [" +
lookupId + "], factory key [" + factoryKey + "], from group with resource name [" +
this.resourceName + "]", ex);
}
}
if (!(bean instanceof BeanFactory)) {
throw new FatalBeanException("Returned bean is not BeanFactory or its subclass. lookup ID [" +
lookupId + "], factory key [" + factoryKey + "], from group with resource name [" +
this.resourceName + "]. Returned object class is [" + bean.getClass().getName() + "]");
}
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. 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).
*/
protected BeanFactory createDefinition(String resourceName, String factoryKey) throws BeansException {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] configResources;
try {
configResources = resourcePatternResolver.getResources(resourceName);
}
catch (IOException e) {
throw new BeanDefinitionStoreException("Error accessing bean definition resource", e);
}
if (configResources.length == 0)
throw new FatalBeanException("Unable to find resource for specified definition. " +
"Group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]");
try {
for (int j = 0; j < configResources.length; j++)
reader.loadBeanDefinitions(configResources[j]);
factory.preInstantiateSingletons();
}
catch (BeansException e) {
throw new FatalBeanException("Unable to load group definition. " +
"Group resource name [" + this.resourceName + "], factory key [" + factoryKey + "]");
}
return factory;
}
/**
* 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 + -