|
From: Andy D. <an...@ma...> - 2005-02-22 16:48:30
|
I'm going to add my 2c and just throw in what we do. Our rich client is
modular, in the sense that if a customer pays for a certain module, then they
get that functionality. To easily support this we split each module into its
own .jar. Our goal is that if a module's .jar is on the classpath, then its
"contributions" automatically becomes a part of the application. Our server
creates a WebStart .jnlp for each customer with their particular set of
module .jars setup for their classpath. Yes, this is basically nothing more
than a plugin architecture we are talking about.
So, how do we approach this from a configuration standpoint, seeing that we've
decided to use Spring and Spring-richclient? Basically how Rob has
described. Each module can specify its own Spring configuration file. We
can automatically detect these by requiring all module .jars to have their
Spring config in the same location and with the same name
(META-INF/context.xml). We then pass this into
FileSystemXmlApplicationContext: "classpath*:/META-INF/context.xml"
At this point we have one big ApplicationContext containing all the beans for
all modules. We now need some way to meaningfully and dynamically connect
the various beans together. Modules do not directly reference beans from
each other, because there is no guarantee that a module is going to be
present - meaning I can't do something like this:
<bean id="modelManager" class="...">
<property name="modelSources">
<list>
<ref bean="fooModuleModel"/>
<ref bean="barModuleModel"/>
...
</list>
</property>
</bean>
because fooModuleModel and/or barModuleModel might not be present in the
ApplicationContext. So, we implement an idea that is similar in spirit to
"extension points". For each "extension point" we define a simple Java
interface, and then the extension point "stakeholder" will query the
ApplicationContext for beans implementing that interface:
Map modelSources =
BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(),
ModelSource.class, false, false);
Which will rake in all beans implementing ModelSource. The interface also
defines a contract that an extension point contributor must implement in
order to meaningfully "contribute" to the extension point. Granted, it would
be nice if Spring provided some automated way to perform this so I wouldn't
have to create dependencies on Spring in my classes (ApplicationContext,
getBeansOfType, etc).
If Spring wanted to automate this "extension point" mechanism such as it
exists in our project, it could provide something like this:
<bean id="modelManager" class="...">
<property name="modelSources" extension-point="com.mypackage.ModelSource"/>
</bean>
Which would automatically build a collection by gathering all beans that
implement the specified interface and injecting the collection into the
"modelSources" property.
- Andy
PS In Spring, this whole idea is currently implemented in "recipe" fashion.
IoC containers like HiveMind make the idea a first class citizen. Actually,
we considered HiveMind, but it is not as mature as Spring and doesn't offer
many of the advanced integration constructs of Spring.
|