介绍
它将其内部bean工厂引用创建为org.springframework.context.ApplicationContext,而不是SingletonBeanFactoryLocator的简单BeanFactory
如何使用
BeanFactoryLocator beanFactoryLocator = ContextSingletonBeanFactoryLocator.getInstance("classPath");
BeanFactoryReference refer = beanFactoryLocator.useBeanFactory("id of bean");
BeanFactory context = refer.getFactory();
源码分析
ContextSingletonBeanFactoryLocator#getInstance
public static BeanFactoryLocator getInstance(String selector) throws BeansException {
// 定位文件的路径
String resourceLocation = selector;
if (resourceLocation == null) {
// 见下面默认路径
resourceLocation = DEFAULT_RESOURCE_LOCATION;
}
// 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 (!ResourcePatternUtils.isUrl(resourceLocation)) {
resourceLocation = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resourceLocation;
}
// 下面是创建
synchronized (instances) {
if (logger.isTraceEnabled()) {
logger.trace("ContextSingletonBeanFactoryLocator.getInstance(): instances.hashCode=" +
instances.hashCode() + ", instances=" + instances);
}
BeanFactoryLocator bfl = instances.get(resourceLocation);
if (bfl == null) {
// 重点看下这里 见下面创建对象
bfl = new ContextSingletonBeanFactoryLocator(resourceLocation);
instances.put(resourceLocation, bfl);
}
return bfl;
}
}
默认路径
private static final String DEFAULT_RESOURCE_LOCATION = "classpath*:beanRefContext.xml";
缓存对象
private static final Map<String, BeanFactoryLocator> instances = new HashMap<String, BeanFactoryLocator>();
创建对象
protected ContextSingletonBeanFactoryLocator(String resourceLocation) {
super(resourceLocation);
}
这里直接调用super对象,也就是SingletonBeanFactoryLocator
下面我们重点说下SingletonBeanFactoryLocator
SingletonBeanFactoryLocator
实现接口
BeanFactoryLocator,里面只有一个行为
BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException;
这个类就是查找和使用定义的工厂
SingletonBeanFactoryLocator的使用方式
<beans>
<bean id="com.mycompany.myapp"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>com/mycompany/myapp/util/applicationContext.xml</value>
<value>com/mycompany/myapp/dataaccess/applicationContext.xml</value>
<value>com/mycompany/myapp/dataaccess/services.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
使用方式
BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("com.mycompany.myapp");
// now use some bean from factory
MyClass zed = bf.getFactory().getBean("mybean");
主要看下useBeanFactory的方法
@Override
public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
synchronized (this.bfgInstancesByKey) {
BeanFactoryGroup bfg = this.bfgInstancesByKey.get(this.resourceLocation);
if (bfg != null) {
bfg.refCount++;
}
else {
// This group definition doesn't exist, we need to try to load it.
if (logger.isTraceEnabled()) {
logger.trace("Factory group with resource name [" + this.resourceLocation +
"] requested. Creating new instance.");
}
// 重点看下这里
BeanFactory groupContext = createDefinition(this.resourceLocation, factoryKey);
// Record its existence now, before instantiating any singletons.
bfg = new BeanFactoryGroup();
bfg.definition = groupContext;
bfg.refCount = 1;
this.bfgInstancesByKey.put(this.resourceLocation, 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) {
this.bfgInstancesByKey.remove(this.resourceLocation);
this.bfgInstancesByObj.remove(groupContext);
throw new BootstrapException("Unable to initialize group definition. " +
"Group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]", ex);
}
}
try {
BeanFactory beanFactory;
if (factoryKey != null) {
beanFactory = bfg.definition.getBean(factoryKey, BeanFactory.class);
}
else {
beanFactory = bfg.definition.getBean(BeanFactory.class);
}
return new CountingBeanFactoryReference(beanFactory, bfg.definition);
}
catch (BeansException ex) {
throw new BootstrapException("Unable to return specified BeanFactory instance: factory key [" +
factoryKey + "], from group with resource name [" + this.resourceLocation + "]", ex);
}
}
}
protected BeanFactory createDefinition(String resourceLocation, String factoryKey) {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
try {
Resource[] configResources = resourcePatternResolver.getResources(resourceLocation);
if (configResources.length == 0) {
throw new FatalBeanException("Unable to find resource for specified definition. " +
"Group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]");
}
reader.loadBeanDefinitions(configResources);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Error accessing bean definition resource [" + this.resourceLocation + "]", ex);
}
catch (BeanDefinitionStoreException ex) {
throw new FatalBeanException("Unable to load group definition: " +
"group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]", ex);
}
return factory;
}
这里说明下,其实还是我们编程式的创建DefaultListableBeanFactory,这里就没啥好讲的,
总结
如果不是web工程使用spring的话,可以使用这种方式
遗憾的是spring5 已经去掉了这种机制:https://jira.spring.io/browse/SPR-15154