Announcement Announcement Module
Collapse
No announcement yet.
FactoryBean that uses computed selector of desired bean? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • FactoryBean that uses computed selector of desired bean?

    During startup the app computes a value and based on this value sets a bean's
    property. Sounds like a job for 'MethodInvokingFactoryBean'. However, what if
    I want to use that computed value to select a particular bean in the context?

    Yup, I'm aware of the getBean(String) method that can be called on a context, and also of the
    various BeanFactoryPostProcessors. I want the container to do it.

    So, how can I accomplish something like the code shown below. 'selectorFactory'
    bean sets the property of 'runTime' to 'kitOne' or 'kitTwo' based on a selector lookup.
    The "BeanSelectorFactoryBean" doesn't exist, I'm just putting it here to show intent.

    I'm looking at the Spring 1.1 "lookup-method" support, but don't see how it would
    help here.


    Code:
    <beans>
        <bean id="runTime" class="research.Main">
            <property name="kit"><ref local="selectorFactory"/></property>
        </bean>
        
        <bean id="selectorFactory" class="org.spr....... BeanSelectorFactoryBean">
            <property name="selector">
              <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
                    <property name="targetObject"><ref local="queryConf"/></property>
                    <property name="targetMethod"><value>getKitName</value></property>
              </bean>
            </property>
        </bean> 
        
        <bean id="queryConf" class="research.conf.QueryConf"/> 
    
        <bean id="kitOne" class="research.kits.KitOne"/>
        <bean id="kitTwo" class="research.kits.KitTwo"/>
    
    </beans>
    Anyway to do this?

    J. Betancourt

  • #2
    I think you should have a look at the AOP stuff here and more specifically the TargetSources and the HotSwappableTargetSource. They're all mentioned in the AOP chapter of the reference documentation. It allows you to switch beans at runtime.

    Implementing a lookup method should also be an option here however. Personally I wouldn't choose for something like a BeanSelectorFactoryBean. I assume you want to decide which bean is going to take care of things each time a the bean receives an invocation? TargetSources or the lookup-method are the ideal way to do this.

    Comment


    • #3
      Alef:

      Thanks, I'll look into those.


      J. Betancourt

      Comment


      • #4
        One thing I notice right away with HotSwappableTargetSource is that Spring will then be very tied in.

        With the approach I was thinking about, the container would stay non-invasive. Not a biggie concern I guess.

        But, I'll keep reading on the swapper and look-up method stuff.

        Comment


        • #5
          Ok, I figured out how to do this using Method Injection. Posting it
          here so that it may benefit someone (even me later on, grin ).

          Code:
          <beans> 
              <bean id="runTime" class="research.Main">         
                  <lookup-method name="createKitOne" bean="kitOne"/>
                  <lookup-method name="createKitTwo" bean="kitTwo"/>    
              </bean> 
              
              <bean id="kitOne" class="research.kits.KitOne"/> 
              <bean id="kitTwo" class="research.kits.KitTwo"/> 
          
          </beans>
          Thus, the target bean 'runTime' will have to declare two methods in the
          class, then based on the programatic selector determined, it will invoke
          one of these new methods. The context bean definition shown above does
          the magic to make those methods actually return the required beans, either
          'kitOne' or 'kitTwo'.

          Code:
          class psuedo code&#58;   
          
          if kitDesiredName is "One"
                 return createKitOne&#40;&#41; 
          else 
                 return createKitTwo&#40;&#41;
          endif;
          This is pretty cool. The code is container agnostic and I didn't have to become an AOP guru yet.

          ---- Josef Betancourt

          Comment


          • #6
            but, sorry to dwell on this.... More on Inversion of Inversion of Control.

            Now my code is still concerned with configuration, the container should be doing that.

            And, I'm probably still not using look-up method correctly, since to do what I want in this scenario I need to have a method per 'kit'. This is not OO. Much easier is just to use ctx.getBean(...), but just as bad.

            I don't see a solution. Since Spring, AFAIK, does not allow run-time arguments directly influencing wiring up, things can get overly complex. That is, there is no getBean(name, args). I don't even see 'HotSwappableTargetSource' being able to get args, they have to be declared in the xml file. (of course, not using xml and doing straight code or script is an option).

            For one time config I'm starting to see a need of something like "BeanSelectorFactoryBean" and also the need to allow args for container stuff, an IoIoC. Oh well, no biggie.

            --- jb

            Comment


            • #7
              Hmmm, I'm not sure.

              Let's take the Hotswappable stuff and the case of failover. I would need the following:

              1. something that decides exactly when to switch the target (in case of a failure or overloaded target)
              2. something that identifier the caller, the callee and the the relationship between the two
              3. something to add the aspect mentioned in 1) to the relationship the two are having.

              I see the wiring up to be an IoC job, but deciding on when to start using the fail over target and when to switch back can't really be done using just configuration.

              Using an AOP introduction you can provide the component deciding on when to switch to a different component with information about the component (the same as with the PoolingTargetSource, where the PoolinConfig introduction provides info about the poolsize) like the current load or whatever you need to decide upon. Secondly, using the targetsources you can implement the component that makes the decision about which bean to return, etcetera, etcetera.

              Well, maybe I'm just blabbering here. Maybe you could provide a bit more info on what the selection criteria are that you're using to decide which of the two Kit beans you're using.

              cheers,
              Alef

              Comment


              • #8
                Alef:

                The selector in my demo scenario is just a String, it comes from a db table.

                While beginning to code a new FactoryBean subclass I stumbled
                on something that already does something close to what I was discussing. Spring, what a great season!

                ObjectFactoryCreatingFactoryBean

                See: http://www.springframework.org/docs/...ctoryBean.html

                Here are the changes:

                Code:
                 <beans>        
                    <!-- "FactoryBean which returns a value which is an ObjectFactory that returns a bean from the BeanFactory" -->
                    <bean id="kit" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"> 
                        <property name="targetBeanName">
                            <!-- invoke the dialog bean to get the desired bean name --> 
                           <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
                                <property name="targetObject"><ref local="dialog"/></property> 
                                <property name="targetMethod"><value>getOption</value></property> 
                          </bean>
                        </property> 
                    </bean> 
                    
                
                    
                    <!-- DB stub; returns a bean name that user selects in a Swing dialog. -->
                    <bean id="dialog" class="proto.KitPromptDialog" singleton="false">  </bean>     
                    
                    <bean id="kitOne" class="proto.OptionOneKit" singleton="true">
                        <property name="msg"><value>actualOne</value></property>
                    </bean>
                
                    <bean id="kitTwo" class="proto.OptionTwoKit" singleton="true">
                        <property name="msg"><value>actualTwo</value></property>
                    </bean>
                
                </beans>

                And here is the demo driver:
                Code:
                    public static void main&#40; String&#91;&#93; args &#41;
                    &#123;
                        ApplicationContext ctx = new ClassPathXmlApplicationContext&#40;"classpath&#58;applicationContext.xml"&#41;;
                        
                        // access the container, in a real app, use DI.       
                        ObjectFactory factory = &#40;ObjectFactory&#41; ctx.getBean&#40;"kit"&#41;;            
                        IKit kit = &#40;IKit&#41; factory.getObject&#40;&#41;;
                        System.out.println&#40;"kit is&#58; " + kit&#41;;
                        System.exit&#40;0&#41;;
                        
                    &#125;


                ---- j. betancourt

                Comment


                • #9
                  Now, if I create a new FactorBean subclass that gives me the bean not a factory
                  the code and the bean definition becomes simpler to understand, perhaps.

                  Code:
                          ApplicationContext ctx = new ClassPathXmlApplicationContext&#40;"classpath&#58;applicationContext.xml"&#41;;       
                                      
                          IKit kit = &#40;IKit&#41; ctx.getBean&#40;"kit"&#41;;
                          System.out.println&#40;"kit is&#58; " + kit&#41;;

                  A try at a BeanSelectorFactoryBean:

                  Code:
                  /**
                   * Similar to ObjectFactoryCreatingFactoryBean but instead returns the actual object not a factory.
                   * @see org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean
                   * 
                   * @author JBETANCOURT
                   */
                  public class BeanSelectorFactoryBean extends AbstractFactoryBean implements BeanFactoryAware  &#123;
                  	
                  	protected String targetBeanName;
                  	protected BeanFactory beanFactory;
                  	
                  	/**
                  	 * Set the name of the target bean.
                  	 * The target has to be a prototype bean. 
                           * TODO why does the target have to be a prototype bean?
                  	 * @param inTargetBeanName
                  	 */
                  	public void setTargetBeanName&#40;String inTargetBeanName&#41; &#123;
                  		this.targetBeanName = inTargetBeanName;
                  	&#125;
                  
                  	/** &#40;non-Javadoc&#41;
                  	 * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory&#40;org.springframework.beans.factory.BeanFactory&#41;
                  	 */
                  	public void setBeanFactory&#40;BeanFactory inBeanFactory&#41; &#123;
                  		this.beanFactory = inBeanFactory;
                  	&#125;
                  	
                  	/** @return the target bean */
                  	protected Object createInstance&#40;&#41; &#123;
                  		return beanFactory.getBean&#40;targetBeanName&#41;;
                  	&#125;
                  
                  	/** &#40;non-Javadoc&#41;
                  	 * @see org.springframework.beans.factory.FactoryBean#getObjectType&#40;&#41;
                  	 */
                  	public Class getObjectType&#40;&#41; &#123;
                  		return null;  // FIXME what to return here?
                  	&#125;
                  
                  &#125;

                  Perhaps, enough on this topic?


                  --- Josef Betancourt

                  Comment

                  Working...
                  X