In Spring framework we provide configuration data using which Spring container can instantiate beans and inject dependencies. Autowiring in Spring means Spring container can automatically resolve collaboration among beans (bean dependencies) by inspecting the contents of the ApplicationContext.
- Spring Autowiring Modes
- Autowiring in Spring
- Enabling @Autowired annotation
- Using @Autowired annotation
- Using @Autowired annotation on setter
- Using @Autowired annotation on constructor
- Using @Autowired annotation on field
- Using @Autowired annotation on arbitrary methods
- required attribute with @Autowired
- Conflict resolution using @Primary with Annotation-based Autowiring
- Conflict resolution using @Qualifier with Annotation-based Autowiring
Spring Autowiring Modes
There are four autowiring modes in Spring framework.
- no- By default there is no autowiring when using XML based confirguration. Bean references must be defined by ref elements.
- byName- In Autowiring by property name, Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean contains a item property (that is, it has a setItem() method), Spring looks for a bean definition named item and uses it to set the property.
- byType- In autowiring byType, Spring autowires a property if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown. If there are no matching beans, nothing happens (the property is not set).
- constructor- Autowiring by constructor is similar to byType but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised.
Autowiring in Spring
For autowiring in Spring there are three options.
- You can choose to autowire using the traditional XML based configuration. See post- Spring Autowiring Example Using XML Configuration for example.
- Autowiring using @Autowired annotation.
- Autowiting using JSR 330’s @Inject annotation. See post Spring Autowiring Using @Inject and @Named Annotations for example.
In this post we’ll see Spring autowiring example using @Autowired annotation.
Enabling @Autowired annotation
1. You can enable autowiring using @Autowired annotation in Spring by registering 'AutowiredAnnotationBeanPostProcessor' class.
<bean class = "org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
2. By using <context:annotation-config/>
element in an XML-based Spring configuration.
<context:annotation-config/> element implicitly registers post-processors. The implicitly registered post-processors
include AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor
and the aforementioned RequiredAnnotationBeanPostProcessor.
3. By using <context:component-scan>
element in an XML-based Spring configuration. The use of
<context:component-scan> implicitly enables the functionality of <context:annotation-config> element.
Most of the time you'll use this element.
4. By using @ComponentScan
annotation if you are using Java based Spring configuration. See example in this
post- Spring @ComponentScan Annotation
Using @Autowired annotation
- You can apply the @Autowired annotation to constructors.
- You can apply the @Autowired annotation to setter methods.
- You can apply @Autowired to fields.
- You can also apply the annotation to methods with arbitrary names and multiple arguments.
Spring @Autowired annotation examples
We’ll see examples of @Autowired using all the above options. In the example there is a class to place order called OrderService and purchase can be done from a Store. In OrderService class dependency for store has to be autowired.
Using @Autowired annotation on setter
@Autowired annotation on a setter method is equivalent to autowiring="byType" in autowiring using configuration file.
public interface OrderService { public void buyItems(); }
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowired on Setter @Autowired public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
public interface IStore { public void doPurchase(); }
import org.springframework.stereotype.Service; @Service public class RetailStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Retail Store"); } }XML Configuration
<?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:component-scan base-package="com.knpcode.springproject.service" /> </beans>
You can use the following class with main method to read the configuration and call the bean method.
public class App { public static void main( String[] args ){ // create context using configuration ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml"); OrderService order = context.getBean(OrderServiceImpl.class); order.buyItems(); // close the context context.close(); } }
Using @Autowired annotation on constructor
@Autowired annotation on a bean's constructor is equivalent to autowiring="constructor" when autowiring using configuration file.
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowired on constructor @Autowired public OrderServiceImpl(IStore store){ this.store = store; } public void buyItems() { store.doPurchase(); } }
If the target bean defines only one constructor, Spring Framework 4.3 onward an @Autowired annotation on such a constructor is no longer necessary. However, if several constructors are available, at least one must be annotated to let the container know which one to use.
Using @Autowired annotation on field
@Autowired annotation on a field is equivalent to autowiring="byType" in autowiring using configuration file.
@Service public class OrderServiceImpl implements OrderService { // Autowiring on a field @Autowired private IStore store; public void buyItems() { store.doPurchase(); } }
Using @Autowired annotation on arbitrary methods
You can also apply the annotation to methods with arbitrary names and multiple arguments.
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on a method @Autowired public void prepare(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
required attribute with @Autowired
By default, autowiring fails when no matching candidate beans are available for a given dependency. The default behavior is to treat annotated methods and fields as required dependencies.
For example in the following bean class if the dependency to store can’t be satisfied an exception is thrown.
@Service public class OrderServiceImpl implements OrderService { @Autowired private IStore store; .. .. }
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl': Unsatisfied dependency expressed through field 'store'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.knpcode.springproject.service.IStore' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
To change this default behavior you can use required = false along with @Autowired annotation. The property is ignored if it cannot be autowired.
@Autowired(required = false) private IStore store;
As of Spring Framework 5.0, you can also use a @Nullable annotation to indicate that the property can be ignored if it cannot be autowired.
@Autowired public void setStore(@Nullable IStore store) { this.store = store; }
Conflict resolution using @Primary with Annotation-based Autowiring
When autowiring by type there may be multiple candidates of the same type in such scenario Spring container won't be able to decide which bean to autowire and throw NoUniqueBeanDefinitionException.
For example if there two stores RetailStore and OnlineStore of type IStore.
@Service public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
Then our example will fail as it won’t be able to determine which store to autowire.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl': Unsatisfied dependency expressed through method 'setStore' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.knpcode.springproject.service.IStore' available: expected single matching bean but found 2: onlineStore,retailStore
Using Spring’s @Primary annotation you can have more control over the selection process. @Primary indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency.
By annotating OnlineStore bean with @Primary annotation you can ensure that it is given preference.
@Service @Primary public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
Conflict resolution using @Qualifier with Annotation-based Autowiring
Spring’s @Qualifier annotation gives more control over the selection process. You can associate qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument.
@Service public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
@Service public class RetailStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Retail Store"); } }
There are two beans of same type Istore, by using @Qualifier annotation you can qualify the bean to be autowired.
@Service public class OrderServiceImpl implements OrderService { private IStore store; @Autowired @Qualifier("retailStore") public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }Output
16:27:57.979 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'onlineStore' 16:27:57.981 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderServiceImpl' 16:27:58.108 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'retailStore' Doing purchase from Retail Store
That's all for the topic Spring Autowiring Using @Autowired Annotation. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Spring Autowiring Using @Inject and @Named Annotations
- Exclude Bean From Autowiring in Spring
- spring-boot-starter-parent in Spring Boot
- Covariant Return Type in Java
- Java throws Clause With Examples
- Deadlock in Java With Examples
- Stable and Unstable Sorting Algorithms
- Hadoop MapReduce Word Count Program
No comments:
Post a Comment