Lessons Learned From Spring’s @Autowired
Last November we got Spring 2.5 and with it the possibility to use annotations for dependency injection (DI). Annotations can be used instead or mixed with the classic application context file(s) based on XML.
If you compare the former more complex XML configurations with what you still have to keep, after using annotations, it's quite amazing how straightforward the XML becomes. For projects with complex DI configurations it is possible to transfer the configuration in steps.
For our ICEfaces Web application e.g. we started with something like this:
<bean id="businessObject"
class="com.test.BusinessObject"
scope="session">
<aop :scoped-proxy/>
<property name="simpleProperty">
Hello World </property> </bean> <bean id="businessObjectAdministration" class="com.test.BusinessObjectAdministration" scope="session"> <aop :scoped-proxy/> <property name="simpleProperty"> Hello Administrators </property> </bean> <bean id="backingBean" class="com.test.BackingBean" scope="session"> <aop :scoped-proxy/> <property name="businessObject"> <ref bean="businessObject" /> </property> </bean> <bean id="backingBeanAdministration" class="com.test.BackingBeanAdministration" scope="session"> <aop :scoped-proxy/> <property name="businessObjectAdministration"> <ref bean="businessObjectAdministration" /> </property> </bean>
This is pretty verbose. The references can also be written in compact syntax, like this:
<property name="businessObject" ref="businessObject" />
Here are the corresponding classes:
package com.test;
public class BusinessObject {
String simpleProperty;
public void setSimpleProperty(String simpleProperty) {
this.simpleProperty = simpleProperty;
}
public String getSimpleProperty() {
return this.simpleProperty;
}
}
package com.test;
public class BusinessObjectAdministration extends
BusinessObject {
}
package com.test;
public class BackingBean {
BusinessObject businessObject;
public void setBusinessObject(BusinessObject businessObject) {
this.businessObject = businessObject;
}
public String getBusinessObject() {
return this.businessObject;
}
}
package com.test;
public class BackingBeanAdministration {
BusinessObjectAdministration businessObjectAdministration;
public void setBusinessObjectAdministration(
BusinessObjectAdministration businessObjectAdministration) {
this.businessObjectAdministration = businessObjectAdministration;
}
public String getBusinessObjectAdministration() {
return this.businessObjectAdministration;
}
}
Each backing bean in this example uses a corresponding business object, whereas BusinessObjectAdministration is a child of BusinessObject.
Adding Annotations
So, what do we have to change to get this annotation stuff working? The reference attributes in the backing beans get an @Autowired. With this a corresponding Spring bean with the same type is searched during the dependency injection. Additionally, we can skip getter and setter for the reference attributes.
public class BackingBean {
@Autowired
BusinessObject businessObject;
...
}
public class BackingBeanAdministration {
@Autowired
BusinessObjectAdministration businessObjectAdministration;
...
}
With this we can also skip the corresponding properties in the application context:
<bean id="backingBean"
class="com.test.BackingBean" scope="session">
<aop :scoped-proxy/>
</bean>
<bean id="backingBeanAdministration"
class="com.test.BackingBeanAdministration"
scope="session">
<aop :scoped-proxy/>
</bean>
Pretty simple. But, when you deploy this you get an exception. Spring will tell you that it has problems to inject the businessObject reference into backingBean.BusinessObject, because there are two matches. We've an inheritance between BusinessObject and BusinessObjectAdministration. So, both are matched in this case.
Matching via type is not the best solution here. But, there's another annotation that allows to name the Spring bean we wanna be used during the dependency injection, called @Qualifier. It has a parameter, that allows to set the bean's name.
When we add this to the backing beans everything works fine.
public class BackingBean {
@Autowired
@Qualifier("businessObject")
BusinessObject businessObject;
...
}
public class BackingBeanAdministration {
@Autowired
@Qualifier("businessObjectAdministration")
BusinessObjectAdministration businessObjectAdministration;
...
}
- Login or register to post comments
- 2524 reads
- Flag as offensive
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)







Comments
Alarmnummer replied on Wed, 2008/05/14 - 6:44am
The problem is that this isn't dependency injection, but a service lookup.
http://martinfowler.com/articles/injection.html
The component is responsible again for figuring out which dependency it wants. In the short run it can be a time safer, but I don't know if this is a good approach in the long run.
Personally I think it is one of the (many) features Spring could live without.
Berry Crawford replied on Wed, 2008/05/14 - 1:18pm
--wrong thread