Ответ
Слоистая архитектура (Layered Architecture) в Spring — это стандартный подход к организации кода, который разделяет ответственность по функциональным областям. Каждый слой имеет строго определенную роль, что делает приложение более модульным, тестируемым и сопровождаемым.
Основные слои и их ответственность:
-
Controller (Веб-слой):
- Роль: Обработка HTTP-запросов и ответов.
- Задачи: Валидация входных данных (DTO), маппинг на объекты, вызов сервисов, возврат данных (JSON/XML) или представлений.
- Аннотации:
@RestController,@Controller,@RequestMapping,@GetMapping,@PostMapping.
-
Service (Слой бизнес-логики):
- Роль: Содержит основную бизнес-логику приложения.
- Задачи: Оркестрация вызовов репозиториев, применение бизнес-правил, управление транзакциями.
- Аннотации:
@Service,@Transactional.
-
Repository / DAO (Слой доступа к данным):
- Роль: Абстракция для работы с хранилищем данных (БД, кэш, внешний API).
- Задачи: Выполнение CRUD-операций, специфических запросов.
- Аннотации:
@Repository, интерфейсы, расширяющиеJpaRepository,CrudRepository.
-
Model / Entity (Слой доменной модели):
- Роль: Представление бизнес-сущностей и структур данных.
- Задачи: Описание объектов, их связей и правил валидации.
- Аннотации:
@Entity,@Table,@Id,@Column.
Пример кода, демонстрирующий взаимодействие слоев:
// 1. МОДЕЛЬ (Entity)
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
// Геттеры, сеттеры, конструкторы
}
// 2. РЕПОЗИТОРИЙ (Repository)
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
// 3. СЕРВИС (Service)
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(String username, String email) {
if (userRepository.findByEmail(email).isPresent()) {
throw new IllegalArgumentException("Email already exists");
}
User newUser = new User(username, email);
return userRepository.save(newUser); // Бизнес-логика + транзакция
}
}
// 4. КОНТРОЛЛЕР (Controller)
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User createUser(@RequestBody @Valid UserCreateRequest request) {
// Валидация DTO происходит автоматически через @Valid
return userService.createUser(request.getUsername(), request.getEmail());
}
}
Преимущества такого разделения:
- Слабая связанность (Loose Coupling): Слои общаются через четкие интерфейсы. Можно заменить реализацию одного слоя (например, БД), не затрагивая другие.
- Простота тестирования: Сервисы можно тестировать с моками репозиториев, контроллеры — с моками сервисов.
- Единая ответственность (Single Responsibility): Каждый класс решает одну задачу.
- Безопасность: Бизнес-логика изолирована от веб-слоя, контроллеры остаются «тонкими».