I am a Spring newbie. I found that sometime we need to construct an object using runtime data, but fixed value is used in constructor inject of Spring. I know I could create a setter method and change the value with it, but I don't think this an elegant solution. Could any one tell me how to do it?
-
2Examples, code snippets, cookies, cash, etc might help. – adarshr Feb 29 '12 at 10:05
-
2http://mattgemmell.com/2008/12/08/what-have-you-tried/ – Feb 29 '12 at 10:22
-
1Might be of help: http://stackoverflow.com/questions/8772585/spring-bean-with-dynamic-constructor-value – quaylar Feb 29 '12 at 10:34
-
1http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023 – Mark Seemann Feb 29 '12 at 11:08
2 Answers
Using SpEL => via Another Bean
<bean id="bank" class="UsBank">
<property name="moneyLeft" value="100"/> <!-- initial value -->
</bean>
<bean id="bet" class="UsDollars" scope="prototype">
<constructor-arg value="#{ bank.moneyLeft }"/>
</bean>
Let's say the bank
bean is injected somewhere, so you have an access to it:
bank.setMoneyLeft( 100 )
Bet currentBet = appContext.getBean( "bet" )
Using SpEL => via Expression
If this argument can to be computed with an arbitrary expression:
<bean id="bet" class="UsDollars" scope="prototype">
<constructor-arg value="#{ T(java.lang.Math).random() * 100.0 }"/>
</bean>
Using SpEL => via System Properties
If your use case allows to use system properties:
<bean id="bet" class="UsDollars" scope="prototype">
<constructor-arg value="#{ systemProperties['moneyLeft'] }"/>
</bean>
to get the bean:
System.setProperty( "moneyLeft", "5000" )
Bet currentBet = appContext.getBean( "bet" )
You can read read more about SpEL.
One thing to note about making a bet
bean prototype => if it is injected into another bean, it (another bean) also needs to be a prototype, or there is some AOP magic that can be used, but it may not be all that important in your case.
If the above bean does not have to be a prototype
(which would mean you would only need a single instance of this bean, but not at the application context creation time), you can remove scope="prototype"
and add a lazy="true"
. That would tell Spring to only attempt to create this bean when it is first referenced.

- 22,149
- 6
- 70
- 81
Generally for this my preference is to make a factory like so:
@Service
public class RuntimeObjectFactoryImpl implements RuntimeObjectFactory {
private final CustomObjectTypeA oA;
private final CustomObjectTypeB oB;
@Autowired
public RuntimeObjectFactoryImpl(final CustomObjectTypeA oA, final CustomObjectTypeB oB) {
this.oA = oA;
this.oB = oB;
}
@Override
public RuntimeObject get(CustomObjectTypeC oC) {
return new RuntimeObject(oA, oB, oC);
}
}
This can be configured in XML aswell (which I would generally recommend over annotations for wiring business services, but it's a more presentable answer here to use annotations). So then at runtime:
RuntimeObject o = runtimeObjectFactory.get(new CustomObjectTypeC(...));

- 2,946
- 8
- 38
- 56