15 - Annotation Based Container Configurations in Spring

15.1 Overview

With Spring 2.5, annotation support has been added and it is possible to configure the beans using annotations.XML configurations are injected after annotations so whenwe use both annotations and XML based configuration, annotations configuration gets overridden byXML configurations.

In this chapter, we will discuss following annotations

  • @Required
  • @Autowired
  • @Qualifier
  • @Resource
  • @PostConstruct
  • @PreDestroy

15.2 Enable Annotation based configuration

We need to turn on the Annotations based configuration because it is off by default. To turn it on add<context: annotation-config/> into a spring XML file.

The changes required in beans.xml we have used in earlier chapters are highlighted below

<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
</beans>

15.3 @Required

The @Required annotation applies only to setter methods of bean propertiesand mandates that property must be populated at the time of dependency resolution either

·Using explicit property value in a bean definition or using ref attributes for the bean

·Usingautowiring feature.

If the value of property is not set,an exception will be raised.

@Required annotation is available in org.springframework.beans.factory.annotation package

15.3.1 Example

Below Student class has a name property whose setter is annotated with @Required annotation

import org.springframework.beans.factory.annotation.Required;
public class Student
{
       private String name ;
       public String getName() {
              return name;
       }
       @Required
       public void setName(String name) {
              this.name = name;
       } 
}

Now it becomes mandatory to set the name property failing to do so will throw an exception

Define the student bean in beans.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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="studentBean" class="Student">
       <property name="name" value="Student A" />
</bean>
</beans>

Test the annotation using TestRequiredAnnotation class like below

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestRequiredAnnotation {
       public static void main(String[] args) {
              ApplicationContext context =
                     new ClassPathXmlApplicationContext("beans.xml");
              Student student = (Student)context.getBean("studentBean");
              System.out.println(student.getName());             
              }
}

Commenting the property tag from bean like below will throw an exception

<bean id="studentBean" class="Student">
              <!-- <property name="name" value="Student A" /> -->
</bean>

15.4 @Autowired

@Autowired annotation is used to auto wire the properties and can be applied on

  • Setter methods
  • Constructors
  • Property
  • Any arbitrary methods
  • Multiple matching Beans

@Autowired annotation has one attribute “required” whose default value is true which means an exception will be thrown when a dependency is not resolved.

15.4.1 @Autowire on setter methods

@Autowire annotation can be added on any traditional setter method and then dependency will be resolved with “byType” auto wire mode. We need not to define explicit dependency using property tag

Example–

Consider a scenario where each Room will be allocated to one student and will have a unique room number. We will add @Autowire annotations on the setter method of the student property

Student.java
publicclass Student {
       private String name ;
       public String getName() {
              return name;
       }
       publicvoid setName(String name) {
              this.name = name;
       }
}

1. Room.java

import org.springframework.beans.factory.annotation.Autowired;
publicclass Room
{
       private String roomNumber;
       private Student allotedTo;
       public String getRoomNumber() {
              return roomNumber;
       }
       publicvoid setRoomNumber(String roomNumber) {
              this.roomNumber = roomNumber;
       }      
public Student getAllotedTo() {
              return allotedTo;
       }
       @Autowired
       publicvoid setAllotedTo(Student allotedTo) {
              this.allotedTo = allotedTo;
       }
       @Override
       public String toString() {
              String name= "";
              if(allotedTo!=null)
              {
                     name= allotedTo.getName();
              }
return "Room [roomNumber=" + roomNumber + ", allotedTo=" + name            + "]";
       }
}

2. Beans.xml file to configure beans. We will not specify any wiring mode

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
       <bean id="allotedTo" class="Student">
              <property name="name" value="Student A" />
       </bean>      
       <bean id="room" class="Room">
              <property name="roomNumber" value="R-101" />
       </bean>      
</beans>

3. TestAutowireAnnotationOnSetter.java class to test @Autowire annotation on setter.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAutowireAnnotationOnSetter{
public static void main(String[] args) {
       ApplicationContext context =
       new ClassPathXmlApplicationContext("beans.xml");
       Room room = (Room)context.getBean("room");
       System.out.println(room);             
       }
}

4. Run TestAutowireAnnotationOnSetter – you will see below output

15.4.2 @Autowire on constructors

@Autowire annotation can be added on constructors similar to setter methods. oncedone, we need not define explicit dependency using constructor-arg tags

Example –

Consider a scenario where each Room will be allocated to one student and will have a unique room number. Room class will have a constructor that takes student object and that constructor will be annotated with @Autowire annotation

1. Student.java

publicclass Student {
       private String name ;
       public String getName() {
              return name;
       }
       publicvoid setName(String name) {
              this.name = name;
       }  
}

2. Room.java

import org.springframework.beans.factory.annotation.Autowired;
publicclass Room
{
       private String roomNumber;
       private Student allotedTo;
       @Autowired
       public Room(Student allotedTo) {
              this.allotedTo = allotedTo;
       }
       public String getRoomNumber() {
              return roomNumber;
       }
       publicvoid setRoomNumber(String roomNumber) {
              this.roomNumber = roomNumber;
       }      
public Student getAllotedTo() {
              return allotedTo;
       }
       publicvoid setAllotedTo(Student allotedTo) {
              this.allotedTo = allotedTo;
       }
       @Override
       public String toString() {
              String name= "";
              if(allotedTo!=null)
              {
                     name= allotedTo.getName();
              }
return "Room [roomNumber=" + roomNumber + ", allotedTo=" + name            + "]";
       }
}

3. Beans.xml file to configure beans. We will not specify any wiring mode

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
       <bean id="allotedTo" class="Student">
              <property name="name" value="Student A" />
       </bean>      
       <bean id="room" class="Room">
              <property name="roomNumber" value="R-101" />
       </bean>      
</beans>

4. TestAutowireAnnotationOnConstructor.java class to test @Autowire annotation on the constructor.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAutowireAnnotationOnConstructor{
public static void main(String[] args) {
       ApplicationContext context =
       new ClassPathXmlApplicationContext("beans.xml");
       Room room = (Room)context.getBean("room");
       System.out.println(room);             
       }
}

5. Run TestAutowireAnnotationOnConstructor – you will see below output

15.4.3 @Autowire on property

@Autowire annotation can be added on public and private properties as well. Spring uses the reflection API to inject the dependencies when added on the property and that is the reason private properties can also be annotated. In this scenario, corresponding setter methods can be removed

Example –

Consider a scenario where each Room will be allocated to one student and will have a unique room number. We will add @Autowire annotations on the private propertyof the student and will omit the corresponding setter as well.

1. Student.java

publicclass Student {
       private String name ;
       public String getName() {
              return name;
       }
       publicvoid setName(String name) {
              this.name = name;
       } 
}

2. Room.java

import org.springframework.beans.factory.annotation.Autowired;
publicclass Room
{
       private String roomNumber;      
@Autowired
private Student allotedTo;
       public String getRoomNumber() {
              return roomNumber;
       }
       publicvoid setRoomNumber(String roomNumber) {
              this.roomNumber = roomNumber;
       }      
public Student getAllotedTo() {
              return allotedTo;
       }      
       @Override
       public String toString() {
              String name= "";
              if(allotedTo!=null)
              {
                     name= allotedTo.getName();
              }
return "Room [roomNumber=" + roomNumber + ", allotedTo=" + name            + "]";
       }
}

3. Beans.xml file to configure beans. We will not specify any wiring mode

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
       <bean id="allotedTo" class="Student">
              <property name="name" value="Student A" />
       </bean>      
       <bean id="room" class="Room">
              <property name="roomNumber" value="R-101" />
       </bean>      
</beans>

4. TestAutowireAnnotationOnProperties.java class to test @Autowire annotation on property.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAutowireAnnotationOnProperties{
public static void main(String[] args) {
       ApplicationContext context =
       new ClassPathXmlApplicationContext("beans.xml");
       Room room = (Room)context.getBean("room");
       System.out.println(room);             
       }
}

5. Run TestAutowireAnnotationOnProperties – you will see below output

15.4.4 @Autowire on arbitrary method and multiple matching beans

@Autowire annotation can be added on arbitrary methods and even on fields of type list or arrays so all the matching beans will be injected.

Example –

Consider a scenario where Hostel can have multiple rooms . Hostel class will have an @Autowired annotated arbitrary method that takes list of Rooms.

1. Room.java

public class Room
{
       private String roomNumber;
       public String getRoomNumber() {
              return roomNumber;
       }
       public void setRoomNumber(String roomNumber) {
              this.roomNumber = roomNumber;
       }
       @Override
       public String toString() {
              return "Room [roomNumber=" + roomNumber + "]";
       }      
}

2. Hostel.java

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
public class Hostel {
       private List<Room> roomsList;      
       @Autowired
       public void addRooms(List<Room> rooms)
       {
              roomsList= rooms;
       }      
       public void displayRooms()
       {
              System.out.println(roomsList); 
} 
}

3. Beans.xml file to configure beans. We will not specify any wiring mode

<?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-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="room1" class="Room">
       <property name="roomNumber" value="R-101"/>
</bean>
<bean id="room2" class="Room">
       <property name="roomNumber" value="R-102"/>
</bean>
<bean id="room3" class="Room">
       <property name="roomNumber" value="R-103"/>
</bean>
<bean id="hostel" class="Hostel" />
</beans>
     }
}

4. TestAutowireAnnotationOnList.java class to test @Autowire annotation on list property.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAutowireAnnotationOnList {
       public static void main(String[] args) {
              ApplicationContext context =
                           new ClassPathXmlApplicationContext("beans.xml");             
              Hostel hostel = (Hostel) context.getBean("hostel");             
              hostel.displayRooms();
              }
}

5. Run TestAutowireAnnotationOnList – you will see below output

15.5 @Autowired with Required=false

@Autowired annotation has one attribute “required” whose default value is true which means an exception will be thrown when a dependency is not resolved. If we want to leave the field unset if no matching bean is found then we can add required attribute as false.

1. Student.java

publicclass Student {
       private String name ;
       public String getName() {
              return name;
       }
       publicvoid setName(String name) {
              this.name = name;
       } 
}

2. Room.java

import org.springframework.beans.factory.annotation.Autowired;
public class Room
{
       private String roomNumber;
       private Student allotedTo;
       public String getRoomNumber() {
              return roomNumber;
       }
       public void setRoomNumber(String roomNumber) {
              this.roomNumber = roomNumber;
       }
       public Student getAllotedTo() {
              return allotedTo;
       }
       @Autowired(required=false)
       public void setAllotedTo(Student allotedTo) {
              this.allotedTo = allotedTo;
       }
       @Override
       public String toString() {
              String name= "";
              if(allotedTo!=null)
              {
                     name= allotedTo.getName();
              }
return "Room [roomNumber=" + roomNumber + ", allotedTo=" + name            + "]";
       }
}

3. Beans.xml file to configure beans. We will not specify any wiring mode

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">      
       <bean id="room" class="Room">
              <property name="roomNumber" value="R-103" />
       </bean>      
</beans>

4. TestAutowireAnnotationWithRequiredFalse.java class to test @Autowire annotation with required as false.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAutowireAnnotationWithRequiredFalse{
public static void main(String[] args) {
       ApplicationContext context =
       new ClassPathXmlApplicationContext("beans.xml");
       Room room = (Room)context.getBean("room");
       System.out.println(room);             
       }
}

5. Run TestAutowireAnnotationWithRequiredFalse – you will see below output

15.6 @Qualifier

@Qualifier annotation is used to select the bean out of all beans satisfy the dependency. For instance, there are multiple student beans configured and all of the beans are candidates when used byType autowire.

In such scenarios we can use @Qualifier annotation with @Autowire so that a filter can be applied and only matching bean will be injected.

If qualifier tag is not defined in bean then bean name will be considered as qualifier

Example –

Consider a scenario where Hostel will have list of two types of rooms list

1. Room.java

public class Room
{
       private String roomNumber;
       public String getRoomNumber() {
              return roomNumber;
       }
       public void setRoomNumber(String roomNumber) {
              this.roomNumber = roomNumber;
       }
       @Override
       public String toString() {
              return "Room [roomNumber=" + roomNumber + "]";
       }      
}

2. Hostel.java

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Hostel {
       private List<Room> deluxeRooms;      
       private List<Room> airCooledRooms;      
       @Autowired
       @Qualifier("deluxeRooms")
       public void addDeluxeRoom(List<Room> deluxeRooms)
       {
              this.deluxeRooms= deluxeRooms;
       }      
       @Autowired
       @Qualifier("aircooled")
       public void addAirCooledRoom(List<Room> airCooledRooms)
       {
              this.airCooledRooms= airCooledRooms;
       }
             public void displayDeluxeRooms()
       {
              System.out.println(deluxeRooms);
       }      
       public void displayAirCooledRooms()
       {
              System.out.println(airCooledRooms);
       }
}

3. Beans.xml file to configure beans. We will not specify any wiring mode

<?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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="deluxeRooms" class="Room">
       <property name="roomNumber" value="R-104"/>
</bean>
<bean id="room1" class="Room">
       <qualifier value="aircooled"/>
       <property name="roomNumber" value="R-101"/>
</bean>
<bean id="room2" class="Room">
       <qualifier value="aircooled"/>
       <property name="roomNumber" value="R-102"/>
</bean>
<bean id="room3" class="Room">
       <qualifier value="aircooled"/>
       <property name="roomNumber" value="R-103"/>
</bean>
<bean id="hostel" class ="Hostel" />
</beans>

4. TestQualifierAnnotation.java class to test @Qualifier annotation on list property.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestQualifierAnnotation {
       public static void main(String[] args) {
              ApplicationContext context =
                           new ClassPathXmlApplicationContext("beans.xml");             
              Hostel hostel = (Hostel) context.getBean("hostel");             
              hostel.displayAirCooledRooms();
              hostel.displayDeluxeRooms();
              }
}

5. Run TestQualifierAnnotation – you will see below output

15.7 @Resource

@Resource annotations can be applied on property,setter methods and has attribute “name” .The default value of name attribute is the property name or the setter method name.

15.8@PostConstruct and @PreDestroy

In earlier chapters we discussed init-method and destroy-method attributes for the bean in the Spring bean configuration file. In these attributes we can specify the name of the methods that gets executed in the life cycle of bean. Similar to these attributes we can use @PostConstruct and @PreDestroy annotations on the methods and the annotated methods gets executed accordingly.

Let's write a bean to use @PostConstruct and @PreDestroy annotations

1. Student.java

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
publicclass Student
{
       private String name ;
       public String getName() {
              return name;
       }
       publicvoid setName(String name) {
              this.name = name;
       }       
       @PostConstruct
       publicvoid init()
       {
       System.out.println("init method annotated with @PostConstruct called !!!");
       }
       @PreDestroy
       publicvoid destroy()
       {
       System.out.println("destroy method annotated with @preDestroy called !!!");
       }      
       publicstaticvoid main(String args[])
       {
              ApplicationContext context =
                           new ClassPathXmlApplicationContext("beans.xml");             
              Student  student  = (Student) context.getBean("student");             
              ((AbstractApplicationContext)context).destroy();             
       }      
}

2. Define bean configuration in beans.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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="student" class ="Student" >
<property name="name" value="Student A" />
</bean>
</beans>

3. Run Student.java

Like us on Facebook