Ответ
Гексагональная архитектура (Порты и адаптеры) — это архитектурный паттерн, который изолирует бизнес-логику (ядро приложения) от внешних зависимостей (БД, UI, внешние API), делая её независимой и легко тестируемой.
Ключевые компоненты:
- Ядро (Domain): Содержит чистую бизнес-логику и модели. Ничего не знает о внешнем мире.
- Порты (Ports): Интерфейсы, которые определяют как ядро может взаимодействовать с внешним миром.
- Входящие порты (Primary/Driving Ports): Для случаев, когда ядро вызывают (например,
UserService). - Исходящие порты (Secondary/Driven Ports): Для случаев, когда ядро обращается вовне (например,
UserRepository).
- Входящие порты (Primary/Driving Ports): Для случаев, когда ядро вызывают (например,
- Адаптеры (Adapters): Реализации портов для конкретных технологий.
- Входящие адаптеры: Контроллеры REST API, CLI, Web-формы.
- Исходящие адаптеры: Реализации репозиториев для JPA, вызовы внешних REST-сервисов.
Схема потока данных:
Внешний мир -> [Входящий адаптер] -> [Входящий порт] -> [Ядро] -> [Исходящий порт] -> [Исходящий адаптер] -> Внешний мир
Пример структуры:
// 1. ЯДРО: Доменный объект
public class User {
private Long id;
private String name;
}
// 2. ЯДРО: Исходящий порт (интерфейс репозитория)
public interface UserRepositoryPort {
User findById(Long id);
}
// 3. ЯДРО: Входящий порт (интерфейс сервиса)
public interface UserServicePort {
User getUser(Long id);
}
// 4. ЯДРО: Реализация бизнес-логики
@Service
public class UserService implements UserServicePort {
private final UserRepositoryPort repository; // Зависимость от порта!
public User getUser(Long id) { return repository.findById(id); }
}
// 5. АДАПТЕР: JPA-реализация исходящего порта
@Repository
public class JpaUserRepositoryAdapter implements UserRepositoryPort {
@PersistenceContext
private EntityManager em;
public User findById(Long id) { return em.find(User.class, id); }
}
// 6. АДАПТЕР: REST-контроллер (входящий адаптер)
@RestController
public class UserController {
private final UserServicePort userService; // Зависимость от порта!
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { return userService.getUser(id); }
}
Главное преимущество: Технологии становятся заменяемыми деталями. Чтобы сменить БД с PostgreSQL на MongoDB, нужно лишь написать новый MongoUserRepositoryAdapter, не трогая ядро.