← Назад к вопросам

Что такое Onion архитектура?

1.0 Junior🔥 111 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Onion Architecture (Луковая архитектура)

Onion Architecture — это архитектурный паттерн, предложенный Jeffrey Palermo, который организует код в слои с радиальной структурой (как слои луковицы).

Основная идея

Код делится на слои, образующие круги. Каждый внешний слой зависит только от слоёв внутри, но никогда наоборот. Внутренние слои полностью независимы от внешних.

       ┌─────────────────────────────┐
       │     Web API / UI             │  Presentation
       └──────────────┬────────────────┘
              ▲       │
              │       ▼
       ┌─────────────────────────────┐
       │  Application Services       │  Application
       └──────────────┬────────────────┘
              ▲       │
              │       ▼
       ┌─────────────────────────────┐
       │   Domain / Business Logic   │  Domain
       │  (Entities, Value Objects)  │  (Core - ничего не импортирует)
       └─────────────────────────────┘
              ▲
              │
       ┌─────────────────────────────┐
       │    Infrastructure           │  Infrastructure
       │  (Database, Email, APIs)    │
       └─────────────────────────────┘

Четыре слоя Onion Architecture

1. Domain Layer (Ядро)

Самый внутренний слой — чистая бизнес-логика, полностью независим от технологий.

// Domain Entity
public class User {
    private final String id;
    private final String email;
    private final String name;
    
    public User(String id, String email, String name) {
        this.id = id;
        this.email = email;
        this.name = name;
    }
    
    // Бизнес-методы
    public boolean isValidEmail() {
        return email.contains("@");
    }
    
    public String getFullInfo() {
        return name + " (" + email + ")";
    }
}

// Domain Value Object
public class Money {
    private final BigDecimal amount;
    private final Currency currency;
    
    public Money(BigDecimal amount, Currency currency) {
        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("Amount cannot be negative");
        }
        this.amount = amount;
        this.currency = currency;
    }
    
    public Money add(Money other) {
        if (!currency.equals(other.currency)) {
            throw new IllegalArgumentException("Different currencies");
        }
        return new Money(amount.add(other.amount), currency);
    }
}

// Domain Service
public interface UserRepository {
    User findById(String id);
}

Правило: Domain слой НЕ импортирует ничего из других слоёв. Никаких зависимостей на фреймворки, БД, REST.

2. Application Layer

Слой бизнес-процессов и use-cases. Здесь координируется работа Domain логики.

// Use Case / Application Service
@Service
public class CreateUserService {
    private final UserRepository userRepository;
    private final EmailService emailService;
    
    public CreateUserService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
    
    // Orchestration логика
    public void execute(CreateUserCommand command) {
        // Валидация
        if (!isValidEmail(command.getEmail())) {
            throw new InvalidEmailException();
        }
        
        // Создаём Domain Entity
        User user = new User(
            generateId(),
            command.getEmail(),
            command.getName()
        );
        
        // Используем Domain Repository
        userRepository.save(user);
        
        // Отправляем уведомление
        emailService.sendWelcomeEmail(user.getEmail());
    }
}

// Ports (Interfaces)
public interface UserRepository {
    void save(User user);
    User findById(String id);
}

public interface EmailService {
    void sendWelcomeEmail(String email);
}

Правило: Application слой зависит только от Domain, не от Infrastructure.

3. Infrastructure Layer

Внешний слой реализации деталей: БД, HTTP клиенты, файловая система.

// Реализация Repository
@Repository
public class JpaUserRepository implements UserRepository {
    
    @Autowired
    private JpaUserEntity userEntity;
    
    @Override
    public void save(User user) {
        UserJpaEntity entity = new UserJpaEntity();
        entity.setId(user.getId());
        entity.setEmail(user.getEmail());
        entity.setName(user.getName());
        userEntity.save(entity);
    }
    
    @Override
    public User findById(String id) {
        UserJpaEntity entity = userEntity.findById(id).orElseThrow();
        return new User(entity.getId(), entity.getEmail(), entity.getName());
    }
}

// Реализация Email Service
@Service
public class SmtpEmailService implements EmailService {
    
    @Autowired
    private JavaMailSender mailSender;
    
    @Override
    public void sendWelcomeEmail(String email) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(email);
        message.setSubject("Welcome!");
        message.setText("Thanks for registering!");
        mailSender.send(message);
    }
}

// HTTP Client
@Service
public class PaymentGatewayAdapter {
    
    @Autowired
    private RestTemplate restTemplate;
    
    public void processPayment(Payment payment) {
        // Вызов внешнего API
        restTemplate.postForObject(
            "https://api.payment.com/charge",
            payment,
            PaymentResponse.class
        );
    }
}

4. Presentation Layer (UI/API)

Внешний слой для взаимодействия с пользователем/системой.

// REST Controller
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @Autowired
    private CreateUserService createUserService;
    
    @PostMapping
    public ResponseEntity<UserDto> createUser(@RequestBody CreateUserRequest request) {
        CreateUserCommand command = new CreateUserCommand(
            request.getEmail(),
            request.getName()
        );
        
        createUserService.execute(command);
        
        return ResponseEntity.status(HttpStatus.CREATED).build();
    }
}

Правила Onion Architecture

  1. Зависимости указывают внутрь (не наружу)

    ❌ Domain импортирует Application/Infrastructure
    ✅ Application импортирует Domain
    ✅ Infrastructure импортирует Domain и Application
    ✅ Presentation импортирует Application
    
  2. Domain Layer полностью независим (чистый код, без фреймворков)

  3. Инверсия зависимостей (DIP) — используй interfaces

    // Application не зависит от конкретной реализации
    public class CreateUserService {
        private final UserRepository userRepository; // Interface!
        
        public CreateUserService(UserRepository repository) {
            this.userRepository = repository;
        }
    }
    
  4. Ports & Adapters — Interface в Application, реализация в Infrastructure

    // Ports (Application слой)
    public interface UserRepository { } // Определена здесь
    
    // Adapters (Infrastructure слой)
    public class JpaUserRepository implements UserRepository { } // Реализована здесь
    

Преимущества

Независимость от фреймворков — Domain логика не привязана к Spring, JPA, etc

Тестируемость — легко писать unit тесты для Domain

Гибкость — легко заменить реализацию (БД, Email сервис)

Понятность — бизнес-логика отделена от технических деталей

Масштабируемость — новые слои легко добавить

Недостатки

Сложность — требует больше файлов и interfaces

Overhead — для простых приложений может быть оверинжиниринг

Кривая обучения — нужно понимать паттерны и принципы

Сравнение с другими архитектурами

OnionHexagonalLayeredClean
Domain центральный✅ Да✅ Да❌ Нет✅ Да
Инверсия зависимостей✅ Да✅ Да❌ Нет✅ Да
Ports/Adapters✅ Да✅ Да❌ Нет✅ Да
СложностьСредняяВысокаяНизкаяВысокая

Пример проекта

src/
├── domain/                    # Core business logic
│   ├── entities/
│   │   └── User.java
│   ├── value-objects/
│   │   └── Money.java
│   └── repositories/          # Interfaces (Ports)
│       └── UserRepository.java
│
├── application/               # Use cases & services
│   ├── services/
│   │   └── CreateUserService.java
│   └── commands/
│       └── CreateUserCommand.java
│
├── infrastructure/            # Technical implementations
│   ├── persistence/
│   │   ├── JpaUserRepository.java
│   │   └── UserJpaEntity.java
│   └── external/
│       └── SmtpEmailService.java
│
└── presentation/              # API / Web
    └── controllers/
        └── UserController.java

Вывод

Onion Architecture — мощный паттерн для создания maintainable, testable и scalable приложений. Ядро (Domain) остаётся чистым от технических деталей, позволяя сосредоточиться на бизнес-логике. Зависимости всегда указывают внутрь, обеспечивая слабую связанность между слоями.

Что такое Onion архитектура? | PrepBro