📄 singletonbeanfactorylocator.java
字号:
/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.access;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* <p>Keyed-singleton implementation of BeanFactoryLocator, which leverages existing
* Spring constructs. This is normally accessed through DefaultLocatorFactory, but may also
* be used directly.</p>
*
* <p>Please see the warning in BeanFactoryLocator's JavaDoc about appropriate usage
* of singleton style BeanFactoryLocator implementations. It is the opinion of the
* Spring team that the use of this class and similar classes is unecessary except
* (sometimes) for a small amount of glue code. Excessive usage will lead to code
* that is more tightly coupled, and harder to modify or test.</p>
*
* <p>In this implementation, a BeanFactory is built up from one or more XML
* definition file fragments, accessed as resources. The default resource name
* searched for is 'classpath*:beanRefFactory.xml', with the Spring-standard
* 'classpath*:' prefix ensuring that if the classpath contains multiple copies
* of this file (perhaps one in each component jar) they will be combined. To
* override the default resource name, instead of using the no-arg
* {@link #getInstance()} method, use the {@link #getInstance(String selector)}
* variant, which will treat the 'selector' argument as the resource name to
* search for.</p>
*
* <p>The purpose of this 'outer' BeanFactory is to create and hold a copy of one
* or more 'inner' BeanFactory or Application Context instances, and allow those
* to be obtained either directly or via an alias. As such, this class provides
* both singleton style access to one or more BeanFactories/ApplicationContexts,
* and also a level of indirection, allowing multiple pieces of code, which are
* not able to work in a Dependency Injection fashion, to refer to and use the
* same target BeanFactory/ApplicationContext instance(s), by different names.<p>
*
* <p>Consider an example application scenario:<br><br>
* <code>com.mycompany.myapp.util.applicationContext.xml</code> - ApplicationContext
* definition file which defines beans for 'util' layer.<br>
* <code>com.mycompany.myapp.dataaccess-applicationContext.xml</code> -
* ApplicationContext definition file which defines beans for 'data access' layer.
* Depends on the above<br>
* <code>com.mycompany.myapp.services.applicationContext.xml</code> -
* ApplicationContext definition file which defines beans for 'services' layer.
* Depends on the above.
*
* <p>In an ideal scenario, these would be combined to create one ApplicationContext,
* or created as three hierarchical ApplicationContexts, by one piece of code
* somewhere at application startup (perhaps a Servlet filter), from which all other
* code in the application would flow, obtained as beans from the context(s). However
* when third party code enters into the picture, things can get problematic. If the
* third party code needs to create user classes, which should normally be obtained
* from a Spring BeanFactory/ApplicationContext, but can handle only newInstance()
* style object creation, then some extra work is required to actually access and
* use object from a BeanFactory/ApplicationContext. One solutions is to make the
* class created by the third party code be just a stub or proxy, which gets the
* real object from a BeanFactory/ApplicationContext, and delegates to it. However,
* it is is not normally workable for the stub to create the BeanFactory on each
* use, as depending on what is inside it, that can be an expensive operation.
* Additionally, there is a fairly tight coupling between the stub and the name of
* the definition resource for the BeanFactory/ApplicationContext. This is where
* SingletonBeanFactoryLocator comes in. The stub can obtain a
* SingletonBeanFactoryLocator instance, which is effectively a singleton, and
* ask it for an appropriate BeanFactory. A subsequent invocation (assuming the
* same classloader is involved) by the stub or another piece of code, will obtain
* the same instance. The simple aliasing mechanism allows the context to be asked
* for by a name which is appropriate for (or describes) the user. The deployer can
* match alias names to actual context names.
*
* <p>Another use of SingletonBeanFactoryLocator, is to demand-load/use one or more
* BeanFactories/ApplicationContexts. Because the definiiton can contain one of more
* BeanFactories/ApplicationContexts, which can be independent or in a hierarchy, if
* they are set to lazy-initialize, they will only be created when actually requested
* for use.
*
* <p>Given the above-mentioned three ApplicationContexts, consider the simplest
* SingletonBeanFactoryLocator usage scenario, where there is only one single
* <code>beanRefFactory.xml</code> definition file:<br>
* <pre>
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
*
* <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>
* </pre>
* The client code is as simple as:
* <pre>
* BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
* BeanFactoryReference bf = bfl.useBeanFactory("com.mycompany.myapp");
* // now use some bean from factory
* MyClass zed = bf.getFactory().getBean("mybean");
* </pre>
* Another relatively simple variation of the <code>beanRefFactory.xml</code> definition file could be:
* <br>
* <pre>
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
*
* <beans>
*
* <bean id="com.mycompany.myapp.util" lazy-init="true"
* class="org.springframework.context.support.ClassPathXmlApplicationContext">
* <constructor-arg>
* <value>com/mycompany/myapp/util/applicationContext.xml</value>
* </constructor-arg>
* </bean>
*
* <!-- child of above -->
* <bean id="com.mycompany.myapp.dataaccess" lazy-init="true"
* class="org.springframework.context.support.ClassPathXmlApplicationContext">
* <constructor-arg>
* <list><value>com/mycompany/myapp/dataaccess/applicationContext.xml</value></list>
* </constructor-arg>
* <constructor-arg>
* <ref bean="com.mycompany.myapp.util"/>
* </constructor-arg>
* </bean>
*
* <!-- child of above -->
* <bean id="com.mycompany.myapp.services" lazy-init="true"
* class="org.springframework.context.support.ClassPathXmlApplicationContext">
* <constructor-arg>
* <list><value>com/mycompany/myapp/dataaccess.services.xml</value></value>
* </constructor-arg>
* <constructor-arg>
* <ref bean="com.mycompany.myapp.dataaccess"/>
* </constructor-arg>
* </bean>
*
* <!-- define an alias -->
* <bean id="com.mycompany.myapp.mypackage"
* class="java.lang.String">
* <constructor-arg>
* <value>com.mycompany.myapp.services</value>
* </constructor-arg>
* </bean>
*
* </beans>
* </pre>
*
* <p>In this example, there is a hierarchy of three contexts created. The (potential)
* advantage is that if the lazy flag is set to true, a context will only be created
* if it's actually used. If there is some code that is only needed some of the time,
* this mechanism can save some resources. Additionally, an alias to the last context
* has been created. Aliases allow usage of the idiom where client code asks for a
* context with an id which represents the package or module the code is in, and the
* actual definition file(s) for the SingletonBeanFactoryLocator maps that id to
* a real context id.
*
* <p>A final example is more complex, with a <code>beanRefFactory.xml</code> for every module.
* All the files are automatically combined to create the final definition.<br>
* <code>beanRefFactory.xml</code> file inside jar for util module:
*
* <p><pre>
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
*
* <beans>
* <bean id="com.mycompany.myapp.util" lazy-init="true"
* class="org.springframework.context.support.ClassPathXmlApplicationContext">
* <constructor-arg>
* <value>com/mycompany/myapp/util/applicationContext.xml</value>
* </constructor-arg>
* </bean>
* </beans>
* </pre>
*
* <code>beanRefFactory.xml</code> file inside jar for data-access module:<br>
* <pre>
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
*
* <beans>
* <!-- child of util -->
* <bean id="com.mycompany.myapp.dataaccess" lazy-init="true"
* class="org.springframework.context.support.ClassPathXmlApplicationContext">
* <constructor-arg>
* <list><value>com/mycompany/myapp/dataaccess/applicationContext.xml</value></list>
* </constructor-arg>
* <constructor-arg>
* <ref bean="com.mycompany.myapp.util"/>
* </constructor-arg>
* </bean>
* </beans>
* </pre>
*
* <code>beanRefFactory.xml</code> file inside jar for services module:<br>
* <pre>
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
*
* <beans>
* <!-- child of data-access -->
* <bean id="com.mycompany.myapp.services" lazy-init="true"
* class="org.springframework.context.support.ClassPathXmlApplicationContext">
* <constructor-arg>
* <list><value>com/mycompany/myapp/dataaccess/services.xml</value></list>
* </constructor-arg>
* <constructor-arg>
* <ref bean="com.mycompany.myapp.dataaccess"/>
* </constructor-arg>
* </bean>
* </beans>
* </pre>
*
* <code>beanRefFactory.xml</code> file inside jar for mypackage module. This doesn't
* create any of its own contexts, but allows the other ones to be referred to be
* a name known to this module:<br>
* <pre>
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
*
* <beans>
* <!-- define an alias -->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -