Professional Scrum Master, Project Manager, IT Business Architect (JEE, Spring, ICEfaces/JSF) Author of the book "ICEfaces 1.8: Next Generation Enterprise Web Development" Rainer has posted 13 posts at DZone. You can read more from them at their website. View Full User Profile

Lessons Learned From Spring’s @Autowired

05.13.2008
| 27154 views |
  • submit to reddit

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;

...
}
References
Published at DZone with permission of its author, Rainer Eschen. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Peter Veentjer replied on Wed, 2008/05/14 - 5: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 - 12:18pm

--wrong thread

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.