Autowiring in Spring means Spring container can automatically resolve collaboration among beans (bean dependencies) by inspecting the contents of the ApplicationContext.
Ways to Autowire in Spring
For autowiring in Spring there are three options.
- You can choose to autowire using the traditional XML based configuration.
- Autowiring using @Autowired annotation. Refer post- Spring Autowiring Using @Autowired Annotation to see example.
- Autowiting using JSR 330’s @Inject annotation. Refer post- Spring Autowiring Using @Inject and @Named Annotations to see example.
In this post we’ll see Spring autowiring example using XML configuration.
Spring autowiring modes
There are four autowiring modes in Spring framework.
- no- By default there is no autowiring when using XML based configuration. 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 property called item (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.
Spring Autowiring example using XML configuration
We’ll see examples of autowiring in Spring where the autowiring mode is configured using XML. In the example there is a class to place order called OrderService and purchase can be done from a Store. In OrderServiceImpl class dependency for store has to be autowired.
Autowiring using byName
When you are autowiring by name the Spring container will look for the bean with the same name or id as defined in the XML to autowire.
public interface OrderService { public void buyItems(); }
public class OrderServiceImpl implements OrderService { private IStore store; public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
public interface IStore { public void doPurchase(); }
public class RetailStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Retail Store"); } }XML Configuration (appContext.xml)
<?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"> <!-- Store bean --> <bean id="store" class="com.knpcode.springproject.service.RetailStore" /> <!-- OrderServiceImpl bean with store bean dependency --> <bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl" autowire="byName" /> </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("orderBean", OrderServiceImpl.class); order.buyItems(); // close the context context.close(); } }Output
16:47:38.923 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [appcontext.xml] 16:47:39.009 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'store' 16:47:39.050 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean' Doing purchase from Retail Store
Autowiring using byType
When you are autowiring by type Spring container looks for the bean with compatible type in the 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"> <!-- Store bean --> <bean id="store" class="com.knpcode.springproject.service.RetailStore" /> <!-- OrderServiceImpl bean with store bean dependency --> <bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl" autowire="byType" /> </beans>
Conflict resolution when autowiring byType
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 are two stores RetailStore and OnlineStore of type Istore.
public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }And both are configured in the XML-
<?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"> <!-- Store bean --> <bean id="retailStore" class="com.knpcode.springproject.service.RetailStore" /> <!-- Store bean --> <bean id="onlineStore" class="com.knpcode.springproject.service.OnlineStore" /> <!-- OrderServiceImpl bean with store bean dependency --> <bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl" autowire="byType" /> </beans>
This results in NoUniqueBeanDefinitionException as Spring container which IStore type bean to autowire.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderBean' defined in class path resource [appcontext.xml]: Unsatisfied dependency expressed through bean property 'store'; 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: retailStore,onlineStore
There are two ways to resolve conflict arising due to having multiple bean definitions of the same type-
- By using primary attribute
- By using Qualifier
Conflict resolution using primary
By using primary attribute you can indicate that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency.
<?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"> <!-- Store bean --> <bean id="retailStore" class="com.knpcode.springproject.service.RetailStore" primary="true"/> <!-- Store bean --> <bean id="onlineStore" class="com.knpcode.springproject.service.OnlineStore" /> <!-- OrderServiceImpl bean with store bean dependency --> <bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl" autowire="byType" /> </beans>
Here primary attribute is used with the RetailStore bean so this bean is given preference while autowiring.
Conflict resolution using Qualifier
Spring’s Qualifier element 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. Qualifier is intended to be used with automatic autowiring though.
<?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/> <!-- Store bean --> <bean id="retailStore" class="com.knpcode.springproject.service.RetailStore"> <qualifier value="rstore"/> </bean> <!-- Store bean --> <bean id="onlineStore" class="com.knpcode.springproject.service.OnlineStore"> <qualifier value="ostore"/> </bean> <!-- OrderServiceImpl bean with store bean dependency --> <bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl" /> </beans>
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class OrderServiceImpl implements OrderService { @Autowired @Qualifier("ostore") private IStore store; public void buyItems() { store.doPurchase(); } }
Autowiring using constructor
Autowiring by constructor is similar to autowiring byType, with constructor type of the constructor argument is used to search the bean with the same type.
<?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"> <!-- Store bean --> <bean id="retailStore" class="com.knpcode.springproject.service.RetailStore" /> <!-- OrderServiceImpl bean with store bean dependency --> <bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl" autowire="constructor" /> </beans>
public class OrderServiceImpl implements OrderService { private IStore store; public OrderServiceImpl(IStore store){ this.store = store; } public void buyItems() { store.doPurchase(); } }Output
18:46:38.298 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [appcontext.xml] 18:46:38.384 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'retailStore' 18:46:38.422 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean' 18:46:38.465 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderBean' via constructor to bean named 'retailStore' Doing purchase from Retail Store
That's all for the topic Spring Autowiring Example Using XML Configuration. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Exclude Bean From Autowiring in Spring
- Advantages and Disadvantages of Autowiring in Spring
- Injecting Prototype Bean into a Singleton Bean in Spring
- Comparable Vs Comparator in Java
- Decompress And Untar Multiple Gzipped files in Java
- Java String replace Method With Examples
- Default Methods in Java Interface
- YARN Fair Scheduler With Example
No comments:
Post a Comment