Stalin Sara
Stalin Sara

Reputation: 1

MethodInvokingFactoryBean- method not getting invoked

I tried writing a test program on MethodInvokingFactoryBean, having 2 beans declared as below.

<bean id="test2" class="test3">
</bean>

<bean id="m2" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" lazy-init="false" depends-on="test4">
    <property name="targetObject"><ref local="test2"></ref></property>
    <property name="targetMethod"><value>execute</value></property>
    <property name="arguments">
       <list>
        <value>abc</value>
        <ref local="test4"></ref>
       </list>
    </property>
</bean>

<bean id="test4" class="test5"></bean>
<bean id="m3"class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" lazy-init="true">
    <property name="targetObject"><ref local="test4"></ref></property>
    <property name="targetMethod"><value>execute</value></property>
    <property name="arguments">
       <list>
          <value>xyz</value>
        </list>
        </property>
</bean>

I am getting the bean via:

test3 obj3 =  (test3) _context.getBean("test2");

The usecase for me here is, before executing the Method execute in test2, I should be able to execute the Method execute lying on bean "test4" , as "test4" is one of my arguments for running execute Method in "test2".

And also, I need everything to be made lazy-init = true.

I tried with the above, but the Method "execute" in test4 is not getting called before executing Method in test2.

Kindly help me to solve this.

Upvotes: 0

Views: 3782

Answers (1)

gpeche
gpeche

Reputation: 22514

execute in test4 is not going to be called as m3 is declared lazy-init="true". The chain of dependencies is as follows:

  • eager bean test2 is independent
  • eager bean test4 is independent
  • eager bean m2 depends on test2 and test4
  • lazy bean m3 depends on test4

So at startup, Spring initializes test2, test4 and then m2. It does not do m3 as it is lazy. Then, when you request bean test2 to the context, it sees that test4 has already been completely initialized and just returns it.

Now, you are saying that you need everything as lazy-init="true", but in fact most of your beans are eager. Would making everything really lazy and changing it in this way fulfill your requirements?

<bean id="test2" class="test3" lazy-init="true" depends-on="m2">
</bean>

<bean id="m2" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" lazy-init="true" depends-on="m3">
    <property name="targetObject"><ref local="test2"></ref></property>
    <property name="targetMethod"><value>execute</value></property>
    <property name="arguments">
       <list>
        <value>abc</value>
        <ref local="test4"></ref>
       </list>
    </property>
</bean>

<bean id="test4" class="test5" lazy-init="true"></bean>
<bean id="m3"class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" lazy-init="true">
    <property name="targetObject"><ref local="test4"></ref></property>
    <property name="targetMethod"><value>execute</value></property>
    <property name="arguments">
        <list>
          <value>xyz</value>
        </list>
    </property>
</bean>

In this way, everything is lazy-init so Spring should not do any initialization by default on startup. Now, the chain of dependencies is:

  • lazy bean test4 is independent
  • lazy bean m3 depends on bean test4
  • lazy bean m2 depends on beans test2, m3 and test4
  • lazy bean test2 depends on bean m2

So when you request bean test2, initialization for m2, m3 and test4 will be triggered. It is not pretty because there is a circular dependency between test2 and m2, but it should work.

Anyway, your setup is quite complicated and if you cannot simplify it, I think you are in the point where Spring starts getting in your way. I recommend you to write a single service in Java that hides the management of those dependencies, so you can remove all those XML and put a single, simple, straightforward bean declaration instead. Something similar to this, where test2Factory hides all the ugliness:

<bean id="test2Factory" class="test2FactoryClass">
   <property name="test4"><bean class="test5"/></property>
</bean>

<bean id="test2" factory-bean="test2Factory" factory-method="getInstance"/>

UPDATE

This is getting messy, you could try declaring some artificial bean to break circularity:

<bean id="rawTest2" class="test3" lazy-init="true">
</bean>

<bean id="m2" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" lazy-init="true" depends-on="m3">
    <property name="targetObject"><ref local="rawTest2"></ref></property>
    <property name="targetMethod"><value>execute</value></property>
    <property name="arguments">
       <list>
        <value>abc</value>
        <ref local="test4"></ref>
       </list>
    </property>
</bean>

<bean id="test2" class="org.springframework.beans.factory.config.PropertyPathFactoryBean" lazy-init="true" depends-on="m2">
    <property name="targetBeanName" value="rawTest2"/>
    <property name="propertyPath" value=" "/><!-- One space inside quotes -->
</bean>

<!-- m3 and test4 stay the same as before -->

Although at this point I would just code the thing in Java...

Upvotes: 2

Related Questions