Wednesday, October 16, 2013

Spring Beans Autowiring

In this post I'm going to write about Autowiring feature in Spring.


Overview:

Generally, in Spring, you will define the beans and inject other beans into their properties by configuring them in xml. For eg, if we have a DAO, UserDAO and a service class UserService, which has a property reference for the DAO, then, the bean configuration would look like this:
<bean id="userDAO" class="com.myorg.service.dao.UserDAO">
</bean>

<bean id="userSvc" class="com.myorg.service.UserService">
      <propertyname="userDAO" ref="userDAO"/>
</bean>

Spring provides a feature called Autowiring, wherein the decision to wire the bean properties could be left to the Spring framework and this saves us a lot of configuration hassle.

There are four types of autowiring:
  1. byName
  2. byType
  3. constructor
  4. autodetect

1. Autowiring - byName:

In this type of wiring, Spring attempts to find the beans which has the same name/id as that of the bean property. In our above DAO/Service example, the UserService has a property userDAO. We can ignore the property config for userDAO by specifying autowiring by name as below:

<bean id="userSvc" class="com.myorg.service.UserService"  autowire="byName">
</bean>

2. Autowiring - byType:

In this type of wiring, Spring attempts to find the beans which have the same type as that of the bean property. This overcomes the disadvantage in 'byName', wherein you should always have the beans with same name/id as that of the property.
<bean id="userSvc" class="com.myorg.service.UserService"  autowire="byType">      
</bean>

Pitfalls of bytpe:

Wiring by type has a disadvantage. If Spring finds more than one matching bean, it will throw an exception. 

To overcome this, you can mark a bean as a primary candidate for autowiring. To get this working, you need to set the 'primary' attribute to true for the bean which you want to autowire and also set this attribute to 'false' for all other beans which have the same type (Since by default for all beans Spring treats this value as true).

Another option is, to set the 'autowire-candidate' to false for those beans which you do not want to be considered for autowiring.

3. Autowiring - constructor:

In this type of wiring, Spring attempts to find the beans which match the same type as that of the constructor arguments of a bean. This eliminates the need for constructor-arg configuration. However, note that when you are using constructor wiring, you cannot use constructor-args for some arguments and wiring for some.

For eg.,the UserDAO will need a datasource object to be injected in its constructor. To configure this, we can use constructor wiring as below:
<bean id="userDAO" class="com.myorg.service.dao.UserDAO" autowire="constructor">
</bean>

Spring will automatically detect the DataSource object defined in the bean configuration file and inject it into the UserDAOs constructor.

4. Autowiring - autodetect:

In this type of wiring, Spring attempts constructor wiring first. It it fails to find a matching bean, then it attempts wiring bytype.


Wiring Nulls:

One interesting feature provided by Spring is that we can also wire a null to a property. This feature is helpful, when the properties have some initial value and we need to nullify them.
<propertyname="country"><null/></property>


In general, you can mix and match different wiring types based on your need and this will help in reducing explicit configuration.

Spring Annotations for Autowiring:

Spring provides two configurations for supporting annotations:
1. context:annotation-config: This configuration when placed in your beans config file, will tell Spring to consider some of the annotations. However, you still need to declare your beans in the config file.

2. context:component-scan: This configuration when placed in your beans config file, will completely eliminate the need for declaring your beans in config file. This config provides autowiring and autodiscovery.

Following are some of the annotations provided by Spring to annotate the beans:
  1. @Component - Indicates that the class is a Spring component.
  2. @Controller  - Indicates that the class is a Spring MVC Controller
  3. @Repository - Indicates that the class is a data repository
  4. @Service  - Indicates that the class is a Service
Also, use the @Autowired configuration to make use of the autowiring ability provided by Spring. Note that @Autowiring always wires by type. If there is more than one bean with the same type, then you can use @Qualifier to remove the ambiguity as explained below:

Lets say there is an interface UserDataService which has two implementations.
public interface UserDataService {
       public User getUser(long userId);
}

@Service
public class UserDataServiceImpl implements UserDataService{
        public User getUser(long userId){ ....  }
}

@Service
public class PrivilegedUserDataServiceImpl implements UserDataService{
        public User getUser(long userId){ ....  }
}

@Controller
public  class UserController {   
        @Autowired
        private UserDataService userSvc;
        
        ...
        
}
Since there are two implementations Spring container will not know which one to bind and it will throw an exception "org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.myorg.service.UserDataService] ".

To overcome this, we can use the @Qualifier annotation to specify which bean we want to be injected. 
public interface UserDataService {
       public User getUser(long userId);
}

@Service
public class UserDataServiceImpl implements UserDataService{
        public User getUser(long userId){ ....  }
}

@Service(value="privileged")
public class PrivilegedUserDataServiceImpl implements UserDataService{
        public User getUser(long userId){ ....  }
}

@Controller
public  class UserController {   
        @Autowired
        @Qualifier("privileged")
        private UserDataService userSvc;
        
        ...
        
}
In the above example, we have provided a name "privileged" to the PrivilegedUserDataServiceImpl and then the same name is used in the @Qualifier annotation.

1 comment:

  1. Nice informative tutorial for the techy people who can quickly refer practical problems of Spring Auto wire Feature & fix problems like in finger tips.

    I feel good get a chance to work with real Gem... of Techy. Hats off Raghu.

    Thanks,
    Kotesh

    ReplyDelete