June 20, 2022

Spring Autowiring Example Using XML Configuration

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.

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-

  1. By using primary attribute
  2. 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

No comments:

Post a Comment