June 29, 2022

Spring @Component, @Service, @Repository, @Controller Annotations

Rather than providing bean definitions and the dependencies in the Spring XML Configuration you can make the Spring framework itself automatically detect the classes by scanning the classpath and register the corresponding bean definition with the container. That can be done using Spring @Component annotation which is a generic annotation and using @Repository, @Service, and @Controller which are specializations of @Component.

Stereotype Annotations in Spring

Spring has stereotype annotations for any Spring-managed component fulfilling a specific role. These stereotype annotations in Spring are @Component, @Service, @Repository and @Controller.

Spring @Component annotation

@Component is a generic stereotype for any Spring-managed component. If you have any class annotated with @Component annotation that will be detected by the component scanning and registered as a bean in the Spring container.

@Component
public class UserService {
  ...
  ...
}

As mentioned it is a generic stereotype annotation there are further specialization of these annotations as per the role and it is recommended to use those annotations. Moreover as per Spring documentation these specialized stereotype annotations may also carry additional semantics in future releases of the Spring Framework.

Spring @Service annotation

Any class in the service layer should be annotated with @Service annotation though the only advantage of using @Service over @Component is more readability.

Spring @Repository annotation

Any class in the DAO (Data Access Object) layer that fulfills the role of a repository should be annotated with @Repository annotation. One of the use of @Repository is enabling automatic translation of exceptions thrown by the underlying persistence technology. Any exception thrown by the underlying persistence technology is wrapped into a DataAccessException instance.

Spring @Controller annotation

Any class acting as a Controller in a Spring Web MVC application should be annotated with the @Controller annotation.

So the thumb rule is rather than using the generic stereotype annotation use the more specific annotations as per the classes in the layered architecture.

  • Presentation layer- @Controller
  • Service layer- @Service
  • Persistence layer- @Repository

Configuration to enable component scanning

If you are using XML configuration then you need to use <context:component-scan> element in your XML, it configures Spring to automatically discover beans and declare them for you. This eliminates the need to use XML to provide bean definitions.

<context:component-scan> element requires base-package attribute. With base-package attribute you need to specify the starting package from where recursive component scanning has to be done.

For example if you have your Service classes with in the package com.knpcode.springexample.service package and DAO classes in com.knpcode.springexample.dao package then you have to provide base-package as com.knpcode.springexample and both the sub-packages service and dao will be scanned recursively.

<context:component-scan base-package="com.knpcode.springexample"/>

If you are using Spring Java configuration then you need to add @ComponentScan annotation along with @Configuration annotation.

@Configuration
@ComponentScan(basePackages="com.knpcode.springexample")
public class AppConfig {
    
}

Spring @Component, @Service, @Repository annotation example

In the example we’ll use the layered architecture where com.knpcode.springexample.dao package contains the DAO classes, com.knpcode.springexample.service package contains the Service classes, com.knpcode.springexample.dto package contains the data transfer objects.

UserService interface
import java.util.List;
import com.knpcode.springexample.dto.User;

public interface UserService {
  public List<User> getUsers();
}
UserServiceImpl class
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.knpcode.springexample.dao.UserDAO;
import com.knpcode.springexample.dto.User;

@Service("userService")
public class UserServiceImpl implements UserService{
  @Autowired
  UserDAO userDAO;

  public List<User> getUsers() {
    return userDAO.getUsers();
  }
}

Notice the use of @Service annotation here. A name is also specified with the @Service meaning that the bean will be registered using that name.

UserDAO interface
import java.util.List;
import com.knpcode.springexample.dto.User;

public interface UserDAO {
  public List<User> getUsers();
}
UserDAOImpl class
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.knpcode.springexample.dto.User;

@Repository
public class UserDAOImpl implements UserDAO {
  public List<User> getUsers() {
    System.out.println("In getUsers method, connect to DB and get data");
    List<User> userList = new ArrayList<User>();
    // Creating User instance locally
    User user = new User();
    user.setFirstName("John");
    user.setLastName("Wick");
    user.setAge(35);
    userList.add(user);
    return userList;
  }
}

Notice the use of @Repository annotation here.

DTO Class (User.java)
public class User {
  private String firstName;
  private String lastName;
  private int age;
  public String getFirstName() {
    return firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public int getAge() {
    return age;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public void setAge(int age) {
    this.age = age;
  }
}
Configuration class
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages="com.knpcode.springexample")
public class AppConfig {

}
To run this example use the following class-
public class App {
  public static void main(String[] args) {
    AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

    UserService userService = context.getBean("userService", UserService.class);
    List<User> users = userService.getUsers();
    for(User user : users) {
      System.out.println("First Name- " + user.getFirstName());
      System.out.println("Last Name- " + user.getLastName());
      System.out.println("Age- " + user.getAge());
    }
    context.close();
  }
}
Output
In getUsers method, connect to DB and get data
First Name- John
Last Name- Wick
Age- 35

That's all for the topic Spring @Component, @Service, @Repository, @Controller Annotations. 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