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