Understanding @Entity, @Repository, and @Service in Spring Boot

In Spring Boot (and the larger Spring Framework), the annotations @Entity, @Repository, and @Service play a key role in structuring and organizing applications using the principles of dependency injection and inversion of control. Here’s an overview of each:


1. @Entity

  • Definition: The @Entity annotation is used in Java Persistence API (JPA) to define a class as a persistent entity. This means the class maps to a table in the database.
  • Key Features:
    • Marks a POJO (Plain Old Java Object) as a JPA entity.
    • Each annotated class is associated with a database table, and each instance of the class represents a row in that table.
    • Requires a primary key, typically annotated with @Id.
  • Example:

package org.kodejava.spring;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class Employee {
    @Id
    private Long id;
    private String name;
    private String role;

    // Getters and setters
}
  • Usage Context: This annotation is part of Jakarta EE (or JPA) and is generally used for classes that model database tables.

2. @Repository

  • Definition: The @Repository annotation indicates that the class is a repository, which is responsible for interacting with the database.
  • Key Features:

    • Used for Data Access Objects (DAO).
    • It helps encapsulate the interaction with the database from the rest of the application.
    • It automatically translates exceptions thrown by the persistence layer into Spring’s unchecked exceptions (like DataAccessException).
  • Example:

package org.kodejava.spring;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    // Custom database queries (if needed)
}
  • Usage Context: Typically, @Repository is used to annotate interfaces or classes that handle data persistence, often enhanced by Spring Data JPA for reducing boilerplate code.

3. @Service

  • Definition: The @Service annotation marks a class as a business service that contains the application’s business logic.
  • Key Features:

    • Indicates that the class is a “service” component in the Service layer.
    • Helps clearly separate business logic from other concerns, such as data persistence or presentation.
    • Works in conjunction with @Component to allow dependency injection.
  • Example:

package org.kodejava.spring;

import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class EmployeeService {
    private final EmployeeRepository repository;

    // Constructor injection of the repository
    public EmployeeService(EmployeeRepository repository) {
        this.repository = repository;
    }

    public List<Employee> getAllEmployees() {
        return repository.findAll();
    }

    public Employee saveEmployee(Employee employee) {
        return repository.save(employee);
    }
}
  • Usage Context: Typically used to encapsulate and reuse business logic.

Summary of Their Responsibilities in an Application Layer:

  • @Entity: Maps a Java class to a database table (used in the Data Model layer).
  • @Repository: Handles database operations (typically at the Data Access layer).
  • @Service: Contains business logic (used in the Service layer).

How These Work Together:

These annotations correspond to different tiers in a common layering structure of a Spring Boot application:
1. Entity: Represents data (e.g., Employee).
2. Repository: Provides the CRUD operations for entities using JPA (e.g., EmployeeRepository).
3. Service: Manages the application’s business logic and interactions (e.g., EmployeeService).

By using these annotations together, you achieve a clean separation of concerns, making the application easier to maintain, test, and scale.

How do I define and inject dependencies using annotations in Spring?

In Spring, you can define and inject dependencies using annotations, which simplifies the process of configuring beans and their relationships. Here’s how you can do it step by step:


1. Define a Dependency with @Component

To define a class as a Spring-managed component (or bean), you annotate it with @Component, which makes the class eligible for dependency injection.

package org.kodejava.spring;

import org.springframework.stereotype.Component;

@Component
public class MyDependency {
    public void doSomething() {
        System.out.println("Dependency logic executed.");
    }
}

Here, @Component tells Spring to manage the lifecycle of this class as a bean.


2. Inject the Dependency with @Autowired

You can inject dependencies into another class by using the @Autowired annotation. It can be applied to:

  • Field injection
  • Constructor injection (recommended)
  • Setter injection

A. Field Injection

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    @Autowired // Spring automatically injects the MyDependency bean here
    private MyDependency myDependency;

    public void performTask() {
        myDependency.doSomething();
    }
}

B. Constructor Injection (Recommended)

Constructor injection is preferred as it makes the dependencies immutable and facilitates better testing.

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    private final MyDependency myDependency;

    @Autowired
    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }

    public void performTask() {
        myDependency.doSomething();
    }
}

Note: From Spring 4.3 onward, if a class has only one constructor, the @Autowired annotation is optional since Spring will automatically use that constructor to inject dependencies.


C. Setter Injection

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    private MyDependency myDependency;

    @Autowired
    public void setMyDependency(MyDependency myDependency) {
        this.myDependency = myDependency;
    }

    public void performTask() {
        myDependency.doSomething();
    }
}

3. Marking Other Components

Instead of using @Component, Spring provides additional stereotype annotations for specific roles, although they work similarly. These are:

  • @Service: Used for service classes.
  • @Repository: Used for data access/DAO components.
  • @Controller: Used for Spring MVC controllers.

Example:

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public void executeService() {
        System.out.println("Executing service logic...");
    }
}

4. Enable Component Scanning

To ensure Spring automatically discovers and registers your components, you need to enable component scanning using the @ComponentScan annotation in your configuration class.

Example configuration class:

package org.kodejava.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "org.kodejava")
public class AppConfig {
}

Alternatively, if you are using Spring Boot, component scanning is enabled automatically for classes within the same package or sub-packages of the main application class annotated with @SpringBootApplication.


5. Example of Application Setup

Here’s a complete example:

Dependency

package org.kodejava.spring;

import org.springframework.stereotype.Component;

@Component
public class HelloWorldService {
    public String sayHello() {
        return "Hello, World!";
    }
}

Service

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class GreetingService {
    private final HelloWorldService helloWorldService;

    @Autowired
    public GreetingService(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
    }

    public void printGreeting() {
        System.out.println(helloWorldService.sayHello());
    }
}

Main Application

package org.kodejava.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        GreetingService greetingService = context.getBean(GreetingService.class);
        greetingService.printGreeting();
    }
}

Configuration

package org.kodejava.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "org.kodejava")
public class AppConfig {
}

Summary of Annotations:

  • @Component: Marks a class as a Spring bean.
  • @Service: A specialization of @Component, typically used for service-layer classes.
  • @Repository: A specialization of @Component, used for DAO/repository classes.
  • @Controller: A specialization of @Component, used for Spring MVC controllers.
  • @Autowired: Marks a dependency to be automatically injected by Spring.
  • @ComponentScan: Specifies the base package(s) for scanning components.

This approach makes dependency management clean and reduces boilerplate code compared to XML-based configurations.


Maven Dependencies

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.2.6</version>
</dependency>

Maven Central