Reputation: 280
I have the following setup:
<bean id="b1" class="SomeClass">
<property name="foo" ref="foo1"/>
</bean>
<bean id="b2" class="SomeClass">
<property name="foo" ref="foo2"/>
</bean>
<bean id="foo1" class="FooClass">
<constructor-arg index="0"><ref bean="dataSource1"/></constructor-arg>
...other constructor args
</bean>
<bean id="foo2" class="FooClass">
<constructor-arg index="0"><ref bean="dataSource2"/></constructor-arg>
...other constructor args
</bean>
Is there a way I can avoid duplicating the FooClass? What I want to do in bean b1 and b2 is add the reference to FooClass but specify the data source all other constructor arguments are the same.
Thanks
Jim
Upvotes: 2
Views: 4623
Reputation: 2488
what you are doing here is , autowiring class with constructure, as aviad said , you can use setter and getter method for your datasource injections
<bean id="foo" class="FooClass">
<constructor-arg index="0">datasource</constructor-arg>
...other constructor args
</bean>
<bean>your datasource bean1</bean>
<bean>your datasource bean2</bean>
and in your implementation you can set your data source as below
@Autowire
private FooClass foo;
foo.setDataSource(datasourcebean1);
you fooClass
public void FooClass(Datasource datasource){
private Datasource datasource;
public void setDatSource(Datasource datasource);
public Datasource getDataSource();
}
EDIT- as per spring documentation, you can pass constructor argument if that doesnt change in terms of its value. But in your case for FooClass you want to pass different datasource at different occasion (hope i get it correctly), so in this case you need to just pass datasouce instance either datasource 1 or datasource 2 during spring initialization, as spring will expect constructor argument while initialing FooClass. later during runtime pass different datasource and set your datasource using setter method.
bean spring config
<bean id="foo" class="FooClass">
<constructor-arg index="0" ref="datasource1"></constructor-arg>
...other constructor args
</bean>
public class FooClass(){
// on spring initialization, it will inject datasource1
public void FooClass(DataSource dataSource){
}
have your setter and getter method for datasource
}
where in your calling service
public class dataBaseInvoke(){
public Datasource datasource2
public FooClass fooClass;
inside method{
fooClass.setDatasource(datasource2);
fooClass.addFoo();
}
}
Upvotes: 1
Reputation: 23893
Considering your implementation, you may want to go for the Bean Definition Inheritance.
From Spring documentation:
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information such as initialization method, static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.
Basically what it says is that you could have a kind of "Template for your Bean Definition" mark it as abstract and use it in other compatible beans as parent to inherit those configurations.
This sample was taken from spring documentation:
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
So at this point this bean isn't instantiated and will be used for bean definition inheritance purpose only.
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
Here you could see that org.springframework.beans.DerivedTestBean
is used to instantiate the bean but it will use all definition of the parent, plus, it will override the property name
. The class doesn't needs to be specified on the parent, but if specified on the parent (inheritedTestBean
) and not on the child (inheritsWithDifferentClass
) the parent class will be used to instantiate the child. Not everything is inherited as we can see here:
A child bean definition inherits constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any initialization method, destroy method, and/or static factory method settings that you specify will override the corresponding parent settings.
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.
Here is a sample using your classes:
<!-- the way you are already using it -->
<bean id="b1" class="SomeClass">
<property name="foo" ref="foo1"/>
</bean>
<!-- if you use it just once, you could declare it inside the bean that uses it -->
<bean id="b2" class="SomeClass">
<property name="foo">
<bean id="foo1" class="FooClass" parent="foo">
<constructor-arg index="0"><ref bean="dataSource1"/></constructor-arg>
</bean>
</property>
</bean>
<!-- here no class definition, only the default configuration -->
<bean id="foo" abstract="true">
<!-- constructor arg 0 is defined only on child beans -->
<constructor-arg index="1" value="whatever1" />
<constructor-arg index="2" value="whatever2" />
<constructor-arg index="3" value="whatever3" />
<constructor-arg index="4" value="whatever4" />
</bean>
<bean id="foo2" class="FooClass">
<constructor-arg index="0"><ref bean="dataSource2"/></constructor-arg>
</bean>
Upvotes: 0
Reputation: 18383
Use abstract bean
<bean id="foo" class="FooClass">
// Set all properties except datasoure
<property name="..." />
</bean>
<bean id="foo1" parent="foo">
<property name="datasource" ref="ds1" />
</bean>
<bean id="foo2" parent="foo">
<property name="datasource" ref="ds2" />
</bean>
Of course you have to use empty contructor instantiation and expose FooClass properties with accessors. If you don't need foo1
and foo2
in other places go for inner beans.
Upvotes: 0
Reputation: 8278
If you want some member of your class to be dynamically initialized\populated on every call to the corresponding getter, you can try the Lookup Method Injection. Read pp. 3.3.4.1 here.
So even if the class that contains the dynamic member was created in scope=singletone (the default for spring bean container) every time you will acces the field that has a lookup method assigned, you will get an appropriate object according to the business logic implemented inside the lookup method.
Also, I found a good example in Spring documentation - I think it is very clear. Take a look at "3.4.6.1 Lookup method injection"
Upvotes: 1