Reputation: 19838
I have 3 projects:
Each of the products depends on the framework, but they don't know each other.
I have 3 spring configuration files: one for each project. The configuration file of each product includes (with <import resource="classpath:/...
) the configuration file of the framework.
In the framework there is a bean called "manager", which has a property List<AnInterface> theList
. The "manager" has a addXxx(anImplementation), which adds elements to the list).
The framework, and each of the product provide implementations of AnInterface
, which have to be added to theList
.
So in the end, when product-a is running, the manager contains implementations from the framework, and from product-a, idem for product-b
What is the best practice to perform this initialization with Spring ?
The only solution I could think about is to create a dedicated class which contructor will take the manager and a list of contributions, and add them to the manager, but it's ugly because 1/ It manipulate external objects in the constructor, 2/ I have to create a dummy class just to initialize other classes... I don't like that.
Upvotes: 1
Views: 3547
Reputation: 19838
I have accepted the answer of Grzegorz because it's a clean solution to my initial problem, but here as an alternate answer, the a technical solution to contribute to a list property of an existing bean.
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="manager"/>
<property name="targetMethod"><value>addXxx</value></property>
<property name="arguments"><list value-type="com.xxx.AnInterface">
<value ref="impl1" />
<value ref="impl2" />
...
</list></property>
</bean>
Upvotes: 1
Reputation: 49171
I think that code should not know about Spring if it is not really needed. Therefore I would do all initialization in Spring config.
We can use bean definition inheritance and property overriding to do it.
Framework class
public class Manager {
private List<AnInterface> theList;
public void init() {
// here we use list initialized by product
}
}
Framework context
<bean id="manager"
init-method="init"
abstract="true"
class="Manager">
<property name="theList">
<list/> <!-- this will be overriden or extnded -->
</property>
</bean>
Product A context
<bean id="managerA"
parent="manager"
scope="singleton"
lazy-init="false">
<property name="theList">
<list>
<ref bean="impl1"/>
<ref bean="impl2"/>
</list>
</property>
</bean>
Watch out for parent and child properties in such configuration. Not all are inherited from parent. Spring documentation specifies:
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.
Moreover, there is also collection merging in Spring so by specifing in child bean
<list merge="true">
you can merge parent and child lists.
I have observed this pattern in a number of projects and some extendable Web frameworks based on Spring.
Upvotes: 2