В чем разница между аннотациями @Repository, @Service и @Controller в Spring?

Ответ

Все три аннотации являются специализациями @Component и регистрируют класс как bean в контексте Spring. Их основное различие — семантическое, для обозначения слоя архитектуры приложения и включения специфического поведения.

Аннотация Слой Назначение и особенности
@Repository Слой доступа к данным (DAO) 1. Помечает класс как репозиторий. 2. Автоматически транслирует исключения конкретных поставщиков данных (например, JDBC SQLException) в непроверяемые исключения Spring DataAccessException.
@Service Слой бизнес-логики 1. Помечает класс как сервис, содержащий бизнес-логику. 2. Не имеет дополнительной технической функциональности по умолчанию, но используется для четкого разделения ответственности. Часто является точкой для применения транзакций (@Transactional).
@Controller Слой представления (веб) 1. Помечает класс как контроллер Spring MVC. 2. Позволяет автоматическое обнаружение методов, обрабатывающих HTTP-запросы (в сочетании с @RequestMapping и др.). 3. Используется для возврата представлений (View). @RestController — это специализация для REST API, которая добавляет @ResponseBody на уровне класса.

Примеры:

// Слой данных
@Repository
public class JpaUserRepository implements UserRepository {
    @PersistenceContext
    private EntityManager em;
    // ... методы доступа к данным
}

// Слой бизнес-логики
@Service
public class UserService {
    @Transactional
    public User createUser(UserDto dto) { ... }
}

// Веб-слой
@Controller
@RequestMapping("/users")
public class UserController {
    @GetMapping
    public String listUsers(Model model) { ... }
}

Использование правильных стереотипных аннотаций улучшает читаемость кода и позволяет Spring применять к ним специфические аспекты.

Ответ 18+ 🔞

Давай разберём эту троицу, а то у новичков иногда мозг вскипает, как чайник забытый. Все эти штуки — @Repository, @Service, @Controller — они, по сути, все под капотом @Component. Spring их видит и говорит: «Ага, вот ещё один боб на моей грядке, сейчас я его в контекст запихну».

Но зачем тогда три разных, если можно везде @Component тыкать? А затем, сука, чтобы не быть распиздяем! Это как маркировка: видишь аннотацию — сразу понимаешь, что этот класс делает и в каком слое архитектуры он сидит. Плюс, Spring для некоторых из них включает дополнительные плюшки.

@Repository — это тот самый чувак, который к базе лезет. Его главная фишка — перевод исключений. Без него, если из недр JDBC вылезет какая-нибудь SQLException, тебе придётся её самому ловить и обрабатывать. А @Repository делает это автоматически: оборачивает все эти техногенные SQLException, JPAException и прочую хуйню в красивые, непроверяемые исключения Spring DataAccessException. Красота! Писал себе репозиторий и не парился.

@Service — это мозги операции, слой бизнес-логики. По технической части — да, почти то же самое, что @Component. Но семантика, блядь! Видишь @Service — понимаешь, что тут живут твои основные правила, расчёты и прочая магия приложения. Это точка, где обычно вешают @Transactional, чтобы всё либо выполнилось, либо откатилось. Чёткое разделение, никакой ерунды.

@Controller — это лицо для веба. Его Spring MVC специально ищет, чтобы понять, какой метод какой HTTP-запрос обрабатывает. Без него @RequestMapping просто так не заведётся. Он заточен под возврат представлений (View). А если тебе REST API пишешь, то есть его брат-близнец — @RestController. Это тот же @Controller, но он по умолчанию ко всем методам @ResponseBody прикручивает, чтобы не писать его каждый раз. Удобно, ёпта!

Вот тебе живые примеры, чтобы вообще всё стало ясно:

// Этот парень работает с базой. @Repository — его метка.
@Repository
public class JpaUserRepository implements UserRepository {
    @PersistenceContext
    private EntityManager em;
    // ... тут он данные таскает, как заправский грузчик
}

// А это уже наш сервис, голова. Вся бизнес-логика тут.
@Service
public class UserService {
    @Autowired
    private UserRepository repository;

    @Transactional // Чтоб всё адекватно коммитилось или откатывалось
    public User createUser(UserDto dto) {
        // ... тут какая-то хитрая проверка и логика перед сохранением
        return repository.save(new User(dto));
    }
}

// Ну а этот красавец общается с внешним миром через HTTP.
@Controller
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService service;

    @GetMapping
    public String listUsers(Model model) {
        model.addAttribute("users", service.getAllUsers());
        return "users/list"; // И говорит, какую вёрстку показывать
    }
}

Короче, используй их по назначению. Код станет чище, архитектура понятнее, а другие разработчики (и ты сам через полгода) не будут материться, пытаясь разобраться, что тут за хуйня происходит. Это ж элементарно, Ватсон!