Though autowiring of the beans can be done using XML configuration for autowiring but Spring goes one step further and provides autowiring using annotations which leads to shorter and more concise configuration.
Broadly Spring provides two ways to annotate beans for autowiring-
- Using @Autowired annotation- It is a spring specific annotation.
- Using @Inject annotation- It is provided by JSR-330 (Dependency Injection for Java) annotations contained in the javax.inject package. Spring supports this annotation.
In this post we'll see Spring autowiring examples using both @Autowired and @Inject annotations.
- Configuration required for autowiring using annotation
- Autowiring in Spring using @Autowired annotation
- Spring @Autowired annotation on setter
- @Autowired annotation on field
- @Autowired annotation on constructor
- @Autowired annotation on arbitrary methods
- @Autowired annotation with required=false
- Conflict resolution using Spring @Qualifier annotation
- Using JSR-330 @Inject annotation
- @Named annotation
- Spring autowiring example with @Inject and @Named annotations
- Are annotations better than XML for configuring Spring?
Configuration required for autowiring using annotation
To enable autowiring using annotation in Spring, you have to register 'AutowiredAnnotationBeanPostProcessor' class.
- You can directly provide this class in xml config-
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
- You can include the <context:annotation-config/> tag in an XML-based Spring configuration
(notice the inclusion of the context namespace in XML). This is the preferred way.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> </beans>
By using <context:annotation-config/> tag following post-processors are implicitly registered AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor and RequiredAnnotationBeanPostProcessor.
- You can include the <context:component-scan/> tag.
Refer Using component-scan in Spring to Automatically Discover Bean to see why <context:component-scan/> should be used instead of <context:annotation-config/>
Autowiring in Spring using @Autowired annotation
- Refer Spring example program using automatic configuration to see how to set up spring project using maven.
Note that @Autowired annotation can be applied on-
- setter method
- constructor
- field
Spring @Autowired annotation on setter
When @Autowired annotation is used on a setter, it is equivalent to autowiring="byType" in autowiring using configuration file.
Here we have a class PayServiceImpl which has a field payment of type IPayment which we have to autowire. Also class CashPayment which implements IPayment interface.
interface IPayService
public interface IPayService { void performPayment(); }
PayServiceImpl class
import org.springframework.beans.factory.annotation.Autowired; public class PayServiceImpl implements IPayService { private IPayment payment; public void performPayment() { // calling method on Ipayment implementing class payment.executePayment(); } public IPayment getPayment() { return payment; } @Autowired public void setPayment(IPayment payment) { this.payment = payment; } }
Here note the @Autowired annotation on setPayment() method.
Interface IPayment
public interface IPayment { void executePayment(); }
CashPayment class
public class CashPayment implements IPayment{ public void executePayment() { System.out.println("Perform Cash Payment - "); } }
XML configuration file
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <bean id="cashPaymentBean" class="org.netjs.prog.CashPayment" /> <!-- Defining PayServiceImpl bean and injecting payment bean --> <bean id="paymentBean" class="org.netjs.prog.PayServiceImpl"> <!-- <property name="payment" ref="cashPaymentBean" /> --> </bean> </beans>
Here note the inclusion of <context:annotation-config/> tag which is required for autowired annotation. Also note that ref for cashPaymentBean is no longer required as a property in paymentBean (it is commented in the config). It will be injected automatically now because of the @Autowired annotation.
You can use the following code to run this program -
import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main( String[] args ){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("appcontext.xml"); // Getting PayServiceImpl IPayService bean = (IPayService) context.getBean("paymentBean"); bean.performPayment(); context.close(); } }
Output
Perform Cash Payment-
@Autowired annotation on field
When @Autowired annotation is used on a property, it is equivalent to autowiring="byType" when autowiring is done using configuration file.
In this case PayServiceImpl will change to have @Autowired annotation on the field. When using @Autowired with field you don't even need the setter method for that field.
PayServiceImpl class
public class PayServiceImpl implements IPayService { @Autowired private IPayment payment; public void performPayment() { // calling method on Ipayment implementing class payment.executePayment(); } public IPayment getPayment() { return payment; } /*public void setPayment(IPayment payment) { this.payment = payment; }*/ }
Rest of the things remain the same as used in the example for @Autowired on setter.
@Autowired annotation on constructor
When @Autowired annotation is used on a bean's constructor, it is equivalent to autowiring="constructor" when autowiring is done using configuration file.
In this case PayServiceImpl will change to have @Autowired annotation on the constructor of the class. When using @Autowired on constructor you don't even need the setter method for that field.
import org.springframework.beans.factory.annotation.Autowired; public class PayServiceImpl implements IPayService { private IPayment payment; // Constructor @Autowired PayServiceImpl(IPayment payment){ this.payment = payment; } public void performPayment() { // calling method on Ipayment implementing class payment.executePayment(); } public IPayment getPayment() { return payment; } /*public void setPayment(IPayment payment) { this.payment = payment; }*/ }
Rest of the things remain the same as used in the example for @Autowired on setter.
@Autowired annotation on arbitrary methods
You can also apply the annotation to methods with arbitrary names and/or multiple arguments, Example as taken from Spring reference doc
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) { this.movieCatalog = movieCatalog; this.customerPreferenceDao = customerPreferenceDao; } // ... }
@Autowired annotation with required=false
The default behavior for the annotation is to treat annotated methods, constructors, and fields as indicating required dependencies. Thus the autowiring fails whenever zero candidate beans are available. You can make the autowiring optional to avoid such errors, this can be done by using required="false" with the @Autowired annotation.
@Autowired(required=false) private IPayment payment;
Conflict resolution using Spring @Qualifier annotation
What if there are more than one bean in the configuration file whose type is compatible with the autowired property. In that case Spring won't be able to decide which bean to use, it will throw an exception instead.
In the above application we had used only one implementation of IPayment, CashPayment so there was no problem in automatically wiring it. Now suppose we have one more implementation of the IPayment interface, Credit Payment. In that case with the current setup you'll get NoUniqueBeanDefinitionException because Spring won't know which Payment class to wire.
CreditPayment class
public class CreditPayment implements IPayment { public void executePayment() { System.out.println("Performing credit payment "); } }
Adding CreditPayment definition in config
<bean id="creditPaymentBean" class="org.netjs.prog.CreditPayment" />
Now if you run the code you will get NoUniqueBeanDefinitionException-
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentBean': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.netjs.prog.IPayment org.netjs.prog.PayServiceImpl.payment; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.netjs.prog.IPayment] is defined: expected single matching bean but found 2: cashPaymentBean,creditPaymentBean at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
In this kind of scenario, to avoid ambiguity you can use @Qualifier annotation to qualify the bean. Suppose you want to inject cashPaymentBean then you can qualify it by passing bean name with the qualifier annotation.
@Qualifier example to avoid NoUniqueBeanDefinitionException error
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class PayServiceImpl implements IPayService { @Autowired @Qualifier("cashPaymentBean") private IPayment payment; public void performPayment() { // calling method on Ipayment implementing class payment.executePayment(); } public IPayment getPayment() { return payment; } /*public void setPayment(IPayment payment) { this.payment = payment; }*/ }
Using JSR-330 @Inject annotation
Instead of @Autowired, @javax.inject.Inject annotation can be used for autowiring in Spring. @Inject annotation is part of the standard JSR-330: Dependency injection for Java. So, if you don't want Spring specific annotations and want to go with standard annotation then use @Inject.
As with @Autowired, it is possible to use @Inject at the class-level, field-level, method-level and constructor-argument level.
Note one thing though. @Inject has no 'required' attribute as provided with @Autowired, so @Inject annotated dependencies can't be optional, an exception will be thrown if they are not fulfilled.
@Named annotation
If you would like to use a qualified name for the dependency that should be injected, instead of @Qualifier you can use @Named annotation which is again part of the standard JSR-330: Dependency injection for Java.
Spring autowiring example with @Inject and @Named annotations
Let's take the same case where we have two payment classes CashPayment and CreditPayment. If you want to make sure that CashPayment bean is the one which is injected then using @Inject and @Named annotations the PayServiceImpl class will look like -
import javax.inject.Inject; import javax.inject.Named; public class PayServiceImpl implements IPayService { @Inject @Named("cashPaymentBean") private IPayment payment; public void performPayment() { // calling method on Ipayment implementing class payment.executePayment(); } public IPayment getPayment() { return payment; } @Inject public void setPayment(@Named("cashPaymentBean")IPayment payment) { this.payment = payment; } }
Note here that @Inject annotation is used with the setter.
Configuration file for the example
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <bean id="cashPaymentBean" class="org.netjs.prog.CashPayment" /> <bean id="creditPaymentBean" class="org.netjs.prog.CreditPayment" /> <!-- Defining PayServiceImpl bean and injecting payment bean --> <bean id="paymentBean" class="org.netjs.prog.PayServiceImpl"> </bean> </beans>
Are annotations better than XML for configuring Spring?
According to the Spring reference doc-
The introduction of annotation-based configurations raised the question of whether this approach is 'better' than XML. The short answer is it depends. The long answer is that each approach has its pros and cons, and usually it is up to the developer to decide which strategy suits them better. Due to the way they are defined, annotations provide a lot of context in their declaration, leading to shorter and more concise configuration. However, XML excels at wiring up components without touching their source code or recompiling them. Some developers prefer having the wiring close to the source while others argue that annotated classes are no longer POJOs and, furthermore, that the configuration becomes decentralized and harder to control.
- Refer Benefits, Disadvantages And Limitations of Autowiring in Spring to know about the benefits and disadvantages of using Autowiring in Spring.
That's all for this topic Autowiring in Spring Using @Autowired and @Inject Annotations. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-
Good Explanation with good knowledge, keep it up. Thank you very much sir.
ReplyDelete