Слоистая архитектура
Слоистая (layered) архитектура — самый распространённый способ организации кода в Java-приложениях. Код делится на слои, каждый из которых отвечает за свою область и зависит только от слоя ниже.
Классические три слоя в Spring Boot:
┌─────────────────────────────┐
│ Controller (@RestController) │ ← HTTP: принять запрос, вернуть ответ
├─────────────────────────────┤
│ Service (@Service) │ ← Бизнес-логика: что нужно сделать
├─────────────────────────────┤
│ Repository (@Repository) │ ← Работа с данными: как сохранить/получить
└─────────────────────────────┘
Правило зависимостей: Controller знает о Service, Service знает о Repository. Но не наоборот. Repository не должен зависеть от Controller — иначе слои теряют смысл.
@RestController // HTTP-слой
class UserController {
private final UserService service;
UserDto get(@PathVariable Long id) { return service.getUser(id); }
}
@Service // Бизнес-слой
class UserService {
private final UserRepository repo;
UserDto getUser(Long id) { return toDto(repo.findById(id)); }
}
@Repository // Данные
interface UserRepository extends JpaRepository<User, Long> {}
Копнуть глубже
DTO и маппинг между слоями. Лучшая практика — каждый слой работает со своими объектами:
- Entity — для JPA/Repository (знает про @Column, @Table)
- DTO — для Controller (что отдаём клиенту, что принимаем)
- Domain объект — для Service (чистая бизнес-логика без JPA-аннотаций)
Маппинг между ними — через конструкторы, или MapStruct (генерирует маппер автоматически). Это защищает от случайного попадания внутренних деталей (пароля, служебных полей) в ответ API.
Проблема «жирного сервиса». В реальных проектах вся бизнес-логика часто собирается в Service — он разрастается до тысяч строк. Чистая архитектура (см. тему «Чистая архитектура») предлагает решение: выделить Domain Layer с чистыми бизнес-объектами и use cases, отделив их от деталей реализации (Spring, JPA).
Тестирование по слоям. Каждый слой тестируется изолированно:
@WebMvcTest— только Controller (MockMvc, без реального сервиса)@Service— чистый unit test с Mockito (без Spring)@DataJpaTest— только Repository (реальная встроенная БД)@SpringBootTest— интеграционный тест всех слоёв вместе
• правило зависимостей между слоями и зачем DTO (если дошёл до 2-го слоя).