XML Spring bean definitions can be verbose. However, an important benefit of using XML is that it completely decouples the components that are being assembled from the mechanism that is assembling them. This is an important part of the POJO programming model and would allow, for example, Spring to be easily replaced by some other framework. This is not true when using annotation-based dependency injection such as that provided by the Guice framework. Components that use those kinds of annotations are tightly coupled to the framework and are definitely not POJOs!
So how can we use a more concise form of XML for configuring dependency injection? In my recent projects, most components had pretty simple wiring rules, e.g. services are injected with repositories; repositories are injected with the SessionFactory or HibernateTemplate etc. Moreover, there is usually a single instance of each bean class and so it's possible to autowire components. We could, therefore, define each service with something like this:
<bean name="fooService" autowire="constructor" class="FooServiceImpl"/>
This is certainly easier that writing multiple <constructor-arg> elements and updating them as the class changes. But we would have to write and maintain similar XML for every component. Why not go one step further and write a "rule" to define beans for all of the components?
Here is an example of such a "rule":
<beans>
<arid:define-beans
package="net.chrisrichardson.arid.example.dao"
autowire="byType"
/>
</beans>
The <arid:define-beans> element (arid is a custom Spring XML namespace) generates bean definitions that use byType autowiring for all of the concrete classes in the net.chrisrichardson.arid.example.dao package. Each bean would, for example, be injected with a Hibernate SessionFactory. The bean name is derived from the concrete class name using a pluggable algorithm - the default algorithm generates a bean called accountDao for the class AccountDaoImpl.
We can be a little more selective about which classes to define as Spring beans by using the <arid:define-beans> element's pattern attribute. This attribute is an AspectJ type pattern. We can use it to match against class names, classes annotations etc. Here is an example of that:
<arid:define-beans
package="net.chrisrichardson.arid.example.domain"
pattern="@ServiceImpl *..*">
</arid:define-beans>
This definition looks for classes in the net.chrisrichardson.arid.example.domain package that have the application-defined @ServiceImpl annotation (package name omitted for brevity) and defines beans that use constructor autowiring. Each bean would, for example, be injected with the necessary DAOs.
But wait, there is more! Let's suppose that one of the classes needs to be injected with some property value. One option is to write a regular bean definition that overrides the definition generated by <arid:define-beans>. Alternatively, you can use <arid:extras> element. In the following example, the moneyTransferService bean uses constructor autowiring and setter injection for the foo property.
<arid:define-beans
package="net.chrisrichardson.arid.example.domain"
pattern="@ServiceImpl *..*">
<arid:extras>
<bean name="moneyTransferService">
<property name="foo" value="bar" />
</bean>
</arid:extras>
</arid:define-beans>
The Spring bean definitions defined by <arid:extras> are merged with the autogenerated bean definition. I'm not sure whether this is worthwhile since it only saves you having to specify the class and autowire attributes but it's something to think about.
This approach can significantly reduce the amount of XML required to configure an application. However, how widely it can be used in your application depends on whether the same dependency injection rules can be consistently applied to multiple beans. Would this help simplify your application's Spring configuration files?
I could see this as being useful - especially in something like AppFuse
where there's a pre-defined set of patterns/conventions to follow.
This sounds interesting...is it a real configuration namespace you have? Or
is it just something that you're proposing? If it's real, where can I get
it and try it out?
Wow. I *love* discovering excellent ideas like this one. Now it's just a
race to get this in production and relieve the xml burden :). Have you
considered approaching the spring team with this as a patch?
If you would like to try it out, you can get the source code from here:
http://code.google.com/p/aridpojos/
This looks money. I was having a discussion with a coworker the other day
about a similar idea. One question though, can this support one class that
is reused multiple times in an app context. For example we have a generic
hibernate dao that we wire up with different parameters like the class to
use, etc. Could this be used in that case?
This is a clever idea, but objects auto-wired in this fashion are only
superficially "more POJO like" than objects wired via annotations (as in
Guice or EJB3 for that matter.) You have a hidden dependency on your DI
runtime (Spring) and on a packaging convention. At least with an annotation
approach, the dependencies are more explicit even if they are intrusive. In
terms of maintainability (code you wrote being maintained by other
developers next year, etc.) one can argue there are advantages to being
more explicit.
What if my interface and impl class reside in different packages? For
example, interface at com.xxx.dao and impl at com.xxx.dao.hibernate (or
com.xxx.dao.ibatis).
Great idea, thank you! I applied in Parancoe framework
(parancoe.dev.java.net) for obtaining auto-discovering of persistent
classes and auto-definition of DAOs. If you are interested, there is a
tutorial in our wiki about using this part of Parancoe:
http://wiki.java.net/bin/view/Projects/ParancoePersistenceTutorial .
Lucio
This is a great idea but I see it difficult to know when it is working
right and to document it for future maintenance. Two ideas for getting some
graphical solution (A picture is worth a thousand words): Spring IDE
integration (maybe not easy or useful), Apache Camel Visualization approach
(see http://activemq.apache.org/camel/visualisation.html). The second
integrates GraphViz through a Maven plugin and Chris, you look a Maven guy
:O)