org.springframework.beans.factory.access

## Class SingletonBeanFactoryLocator

- java.lang.Object
- - org.springframework.beans.factory.access.SingletonBeanFactoryLocator

- All Implemented Interfaces:
    BeanFactoryLocator
  Direct Known Subclasses:
    ContextSingletonBeanFactoryLocator

      public class SingletonBeanFactoryLocator
      extends Object
      implements BeanFactoryLocator

  Keyed-singleton implementation of `BeanFactoryLocator`, which accesses shared Spring `BeanFactory` instances.

  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 unnecessary 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.

  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 `getInstance()` method, use the `getInstance(String selector)` variant, which will treat the 'selector' argument as the resource name to search for.

  The purpose of this 'outer' BeanFactory is to create and hold a copy of one or more 'inner' BeanFactory or ApplicationContext 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.

  Consider an example application scenario:

  - `com.mycompany.myapp.util.applicationContext.xml` - ApplicationContext definition file which defines beans for 'util' layer.
  - `com.mycompany.myapp.dataaccess-applicationContext.xml` - ApplicationContext definition file which defines beans for 'data access' layer. Depends on the above.
  - `com.mycompany.myapp.services.applicationContext.xml` - ApplicationContext definition file which defines beans for 'services' layer. Depends on the above.

  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 class loader 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.

  Another use of SingletonBeanFactoryLocator, is to demand-load/use one or more BeanFactories/ApplicationContexts. Because the definition 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.

  Given the above-mentioned three ApplicationContexts, consider the simplest SingletonBeanFactoryLocator usage scenario, where there is only one single `beanRefFactory.xml` definition file:

      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.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>

  The client code is as simple as:

       BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
       BeanFactoryReference bf = bfl.useBeanFactory("com.mycompany.myapp");
       // now use some bean from factory
       MyClass zed = bf.getFactory().getBean("mybean");

  Another relatively simple variation of the `beanRefFactory.xml` definition file could be:

      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.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>

  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.

  A final example is more complex, with a `beanRefFactory.xml` for every module. All the files are automatically combined to create the final definition.

  `beanRefFactory.xml` file inside jar for util module:

      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.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>

  `beanRefFactory.xml` file inside jar for data-access module:

      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.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>

  `beanRefFactory.xml` file inside jar for services module:

      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.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>

  `beanRefFactory.xml` 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:

      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

       <beans>
         <!-- define an alias for "com.mycompany.myapp.services" -->
         <alias name="com.mycompany.myapp.services" alias="com.mycompany.myapp.mypackage"/>
       </beans>

  Author:
    Colin Sampaleanu, Juergen Hoeller
  See Also:
    `ContextSingletonBeanFactoryLocator`, `DefaultLocatorFactory`

- - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `protected static Log` | `logger`

  - ### Constructor Summary

    Constructors
    Modifier | Constructor and Description
    --- | ---
    `protected` | `SingletonBeanFactoryLocator(String resourceLocation)` Constructor which uses the the specified name as the resource name of the definition file(s).

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `protected BeanFactory` | `createDefinition(String resourceLocation, String factoryKey)` 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 void` | `destroyDefinition(BeanFactory groupDef, String selector)` Destroy definition in separate method so subclass may work with other definition types.
    `static BeanFactoryLocator` | `getInstance()` Returns an instance which uses the default "classpath*:beanRefFactory.xml", as the name of the definition file(s).
    `static BeanFactoryLocator` | `getInstance(String selector)` Returns an instance which uses the the specified selector, as the name of the definition file(s).
    `protected void` | `initializeDefinition(BeanFactory groupDef)` Instantiate singletons and do any other normal initialization of the factory.
    `BeanFactoryReference` | `useBeanFactory(String factoryKey)` Use the `BeanFactory` (or derived interface such as `ApplicationContext`) specified by the `factoryKey` parameter.

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Field Detail

    - #### logger

          protected static final Log logger

  - ### Constructor Detail

    - #### SingletonBeanFactoryLocator

          protected SingletonBeanFactoryLocator(String resourceLocation)

      Constructor which uses the the specified name as the resource name of the definition file(s).
      Parameters:
        `resourceLocation` - the Spring resource location to use (either a URL or a "classpath:" / "classpath*:" pseudo URL)

  - ### Method Detail

    - #### getInstance

          public static BeanFactoryLocator getInstance()
                                                throws BeansException

      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 context ClassLoader's `getResources` method with this name will be combined to create a BeanFactory definition set.
      Returns:
        the corresponding BeanFactoryLocator instance
      Throws:
        `BeansException` - in case of factory loading failure

    - #### getInstance

          public static BeanFactoryLocator getInstance(String selector)
                                                throws BeansException

      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 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.
      Parameters:
        `selector` - the name of the resource(s) which will be read and combined to form the definition for the BeanFactoryLocator instance. Any such files must form a valid BeanFactory definition.
      Returns:
        the corresponding BeanFactoryLocator instance
      Throws:
        `BeansException` - in case of factory loading failure

    - #### useBeanFactory

          public BeanFactoryReference useBeanFactory(String factoryKey)
                                              throws BeansException

      Description copied from interface: `BeanFactoryLocator`
      Use the `BeanFactory` (or derived interface such as `ApplicationContext`) specified by the `factoryKey` parameter.

      The definition is possibly loaded/created as needed.

      Specified by:
        `useBeanFactory` in interface `BeanFactoryLocator`
      Parameters:
        `factoryKey` - a resource name specifying which `BeanFactory` the `BeanFactoryLocator` must return for usage. The actual meaning of the resource name is specific to the implementation of `BeanFactoryLocator`.
      Returns:
        the `BeanFactory` instance, wrapped as a `BeanFactoryReference` object
      Throws:
        `BeansException` - if there is an error loading or accessing the `BeanFactory`

    - #### createDefinition

          protected BeanFactory createDefinition(String resourceLocation,
                                     String factoryKey)

      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).

      The default implementation simply builds a `DefaultListableBeanFactory` and populates it using an `XmlBeanDefinitionReader`.

      This method should not instantiate any singletons. That function is performed by `initializeDefinition()`, which should also be overridden if this method is.

      Parameters:
        `resourceLocation` - the resource location for this factory group
        `factoryKey` - the bean name of the factory to obtain
      Returns:
        the corresponding BeanFactory reference

    - #### initializeDefinition

          protected void initializeDefinition(BeanFactory groupDef)

      Instantiate singletons and do any other normal initialization of the factory. Subclasses that override `createDefinition()` should also override this method.
      Parameters:
        `groupDef` - the factory returned by `createDefinition()`

    - #### destroyDefinition

          protected void destroyDefinition(BeanFactory groupDef,
                               String selector)

      Destroy definition in separate method so subclass may work with other definition types.
      Parameters:
        `groupDef` - the factory returned by `createDefinition()`
        `selector` - the resource location for this factory group