In this example, I’ll show how to do an Annotation Based Spring configuration to define beans and auto wire them together.
Use Case
The Use Case we are going to work on is to fetch list of employees from a service. The service inturn fetch it from data access object.
Creating a Maven Project
First create a simple Maven project by skipping archtype selection in STS.
Add below pom.xml file which can be found at the root of the project.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.techstackjournal</groupId>
<artifactId>annotation-based</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Creation of Model Class
We need a POJO class to instantiate multiple employee objects which are queried from database.
package com.techstackjournal.model;
public class Employee {
private String employeeId;
private String firstName;
private String lastName;
private String email;
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(String employeeId, String firstName, String lastName, String email) {
super();
this.employeeId = employeeId;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public String getEmployeeId() {
return employeeId;
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Employee [employeeId=" + employeeId + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email
+ "]";
}
}
Creating a Data Access Layer
In this data access layer, we will take code to interface approach while creating the EmployeeDAO and its implementation EmployeeDAOImpl.
package com.techstackjournal.dao;
import java.util.List;
import com.techstackjournal.model.Employee;
public interface EmployeeDAO {
List<Employee> findAll();
}
Since this class supposedly fetch data from database, we annotate this class with @Repository
annotation, though we will be just mocking the data for simplicity and to focus on the subject.
package com.techstackjournal.dao;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.techstackjournal.model.Employee;
@Repository("employeeDao")
public class HibernateEmployeeDAOImpl implements EmployeeDAO {
public List<Employee> findAll() {
List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee("1", "John", "Doe", "john.doe@techstackjournal.com"));
employees.add(new Employee("2", "Jane", "Doe", "jane.doe@techstackjournal.com"));
return employees;
}
}
Creating Service Layer
Similar to the data access layer, in service layer too we will code to interfaces. We’ll be creating EmployeeService
which demands the findAll
method to be implemented. The EmployeeServiceImpl
implements this class and provides the implementation to findAll
method.
package com.techstackjournal.service;
import java.util.List;
import com.techstackjournal.model.Employee;
public interface EmployeeService {
List<Employee> findAll();
}
Service Implementation and Autowire on Member
Since this class acts as the placeholder for the business logic, we will annotate this class using @Service annotation.
This class needs an instance of EmployeeDAO
. As you must be knowing, we can provide the dependencies in 3 ways using annotations. In this particular code snippet, we will provide the dependency through annotating the member variable using @Autowired
. You can find other 2 approaches at the end of this article.
package com.techstackjournal.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.techstackjournal.dao.EmployeeDAO;
import com.techstackjournal.model.Employee;
@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeDAO employeeDao;
public EmployeeServiceImpl(EmployeeDAO employeeDao) {
this.employeeDao = employeeDao;
System.out.println("constructor injection " + employeeDao);
}
public List<Employee> findAll() {
return employeeDao.findAll();
}
public void setEmployeeDao(EmployeeDAO employeeDao) {
System.out.println("setter injection " + employeeDao);
this.employeeDao = employeeDao;
}
}
Creating Application Context XML
Inside the applicationContext.xml file, with the help of <context:annotation-config />
tag, we tell Spring that we are using Annotation Configuration to define Spring beans.
Using <context:component-scan />
tag, we tell Spring where to look for Spring beans. We specify the package location to scan using base-package
attribute. If you want Spring to scan only selected packages, you can write all of them separating them with a comma.
<?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 />
<context:component-scan
base-package="com.techstackjournal" />
</beans>
Application Class
In this application class, we get the list of employees from the EmployeeService
object, which we obtain from ApplicationContext
.
package com.techstackjournal.app;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.techstackjournal.model.Employee;
import com.techstackjournal.service.EmployeeService;
public class Application {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
EmployeeService service = appContext.getBean("employeeService", EmployeeService.class);
List<Employee> employees = service.findAll();
for (Employee employee : employees) {
System.out.println(employee);
}
}
}
Autowire using Setter Method
In the above example, we saw the auto wiring using member. In this example, we’ll explore the setter method injection of dependencies.
To enable the setter injection, we need to provide a setter method that initialize the dependency, in our case it’s EmployeeDAO and annotate that setter method using @Autowired
annotation within EmployeeServiceImpl class.
package com.techstackjournal.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.techstackjournal.dao.EmployeeDAO;
import com.techstackjournal.model.Employee;
@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeDAO employeeDao;
public List<Employee> findAll() {
return employeeDao.findAll();
}
@Autowired
public void setEmployeeDao(EmployeeDAO employeeDao) {
this.employeeDao = employeeDao;
}
}
Output:
Employee [employeeId=1, firstName=John, lastName=Doe, email=john.doe@techstackjournal.com]
Employee [employeeId=2, firstName=Jane, lastName=Doe, email=jane.doe@techstackjournal.com]
Autowire using Constructor
To Autowire using a constructor, firstly we need to add a constructor which takes the dependency as an argument and initialize it within its body, secondly you need to add the @Autowired annotation to the constructor.
However, starting from Spring 4.3 onwards, if you have only 1 constructor in the class, auto wiring will happen implicitly.
Implicit Constructor Injection
Since we have only 1 constructor in the below version of EmployeeServiceImpl
, implicit constructor injection will take place to fulfill the dependency of EmployeeServiceImpl
by providing it EmployeeDAO
bean.
package com.techstackjournal.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.techstackjournal.dao.EmployeeDAO;
import com.techstackjournal.model.Employee;
@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeDAO employeeDao;
public EmployeeServiceImpl(EmployeeDAO employeeDao) {
this.employeeDao = employeeDao;
}
public List<Employee> findAll() {
return employeeDao.findAll();
}
}
Explicit Constructor Injection
Since we have 2 constructors in the below version of EmployeeServiceImpl
, we must explicitly tell Spring Container which constructor it should use to fulfill the dependencies. As the second constructor with EmployeeDAO
argument is the one that we need for constructor injection, we define that constructor with @Autowired
annotation.
package com.techstackjournal.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.techstackjournal.dao.EmployeeDAO;
import com.techstackjournal.model.Employee;
@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeDAO employeeDao;
public EmployeeServiceImpl() {
}
@Autowired
public EmployeeServiceImpl(EmployeeDAO employeeDao) {
this.employeeDao = employeeDao;
System.out.println("constructor injection " + employeeDao);
}
public List<Employee> findAll() {
return employeeDao.findAll();
}
}