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

Что такое событийно-управляемая архитектура?

2.0 Middle🔥 121 комментариев
#SOLID и паттерны проектирования#Spring Framework

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

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

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

Событийно-управляемая архитектура

Событийно-управляемая архитектура (Event-Driven Architecture) — это парадигма проектирования систем, где компоненты взаимодействуют друг с другом посредством обмена событиями. Вместо прямых вызовов методов (синхронная связь), компоненты создают события, на которые подписываются другие части системы.

Основные компоненты

  1. Event Source — компонент, создающий события
  2. Event Handler — компонент, обрабатывающий события
  3. Event Channel — способ доставки события (очередь, шина, тема)
  4. Event Dispatcher — координатор, управляющий маршрутизацией событий

Пример: простое событие

// 1. Определение события
public class UserRegisteredEvent {
    private String userId;
    private String email;
    private LocalDateTime timestamp;
    
    public UserRegisteredEvent(String userId, String email) {
        this.userId = userId;
        this.email = email;
        this.timestamp = LocalDateTime.now();
    }
    
    public String getUserId() { return userId; }
    public String getEmail() { return email; }
    public LocalDateTime getTimestamp() { return timestamp; }
}
// 2. Событийная шина (публикатор)
public interface EventBus {
    void publish(Object event);
    <T> void subscribe(Class<T> eventType, EventHandler<T> handler);
}

public interface EventHandler<T> {
    void handle(T event);
}
// 3. Простая реализация EventBus
public class SimpleEventBus implements EventBus {
    private final Map<Class<?>, List<EventHandler<?>>> handlers = new ConcurrentHashMap<>();
    
    @Override
    public void publish(Object event) {
        Class<?> eventType = event.getClass();
        List<EventHandler<?>> eventHandlers = handlers.get(eventType);
        
        if (eventHandlers != null) {
            eventHandlers.forEach(handler -> {
                @SuppressWarnings("unchecked")
                EventHandler<Object> typedHandler = (EventHandler<Object>) handler;
                typedHandler.handle(event);
            });
        }
    }
    
    @Override
    public <T> void subscribe(Class<T> eventType, EventHandler<T> handler) {
        handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()).add(handler);
    }
}
// 4. Event Source — создаёт события
@Service
public class UserService {
    private final EventBus eventBus;
    private final UserRepository userRepository;
    
    public UserService(EventBus eventBus, UserRepository userRepository) {
        this.eventBus = eventBus;
        this.userRepository = userRepository;
    }
    
    public void registerUser(String email, String password) {
        // Бизнес-логика
        User user = new User(UUID.randomUUID().toString(), email, password);
        userRepository.save(user);
        
        // Публикация события
        eventBus.publish(new UserRegisteredEvent(user.getId(), email));
    }
}
// 5. Event Handlers — обрабатывают события
@Service
public class EmailNotificationService {
    private final EmailService emailService;
    
    public EmailNotificationService(EventBus eventBus, EmailService emailService) {
        this.emailService = emailService;
        // Подписка на событие
        eventBus.subscribe(UserRegisteredEvent.class, this::onUserRegistered);
    }
    
    private void onUserRegistered(UserRegisteredEvent event) {
        emailService.sendWelcomeEmail(event.getEmail());
        System.out.println("Welcome email sent to " + event.getEmail());
    }
}

@Service
public class AuditService {
    private final AuditRepository auditRepository;
    
    public AuditService(EventBus eventBus, AuditRepository auditRepository) {
        this.auditRepository = auditRepository;
        // Другой обработчик для того же события
        eventBus.subscribe(UserRegisteredEvent.class, this::onUserRegistered);
    }
    
    private void onUserRegistered(UserRegisteredEvent event) {
        auditRepository.save(new AuditLog("User registered", event.getUserId(), event.getTimestamp()));
        System.out.println("Audit log created for user " + event.getUserId());
    }
}

Spring Events

Spring Framework встроил поддержку событий:

// Spring Event
public class UserRegisteredEvent extends ApplicationEvent {
    private String userId;
    private String email;
    
    public UserRegisteredEvent(Object source, String userId, String email) {
        super(source);
        this.userId = userId;
        this.email = email;
    }
    
    public String getUserId() { return userId; }
    public String getEmail() { return email; }
}

// Event Publisher
@Service
public class UserService {
    private final ApplicationEventPublisher eventPublisher;
    
    public UserService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    
    public void registerUser(String email, String password) {
        // Бизнес-логика
        User user = new User(UUID.randomUUID().toString(), email, password);
        
        // Публикация события
        eventPublisher.publishEvent(new UserRegisteredEvent(this, user.getId(), email));
    }
}

// Event Listener
@Component
public class EmailNotificationListener {
    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        System.out.println("Sending email to " + event.getEmail());
    }
}

Асинхронные события

// Асинхронная обработка событий
@Component
public class AsyncEventListener {
    @EventListener
    @Async  // Выполнится в отдельном потоке
    public void onUserRegistered(UserRegisteredEvent event) {
        // Может быть долгой операцией
        sendWelcomeEmail(event.getEmail());
        createUserPreferences(event.getUserId());
    }
}

Message Brokers (RabbitMQ, Kafka)

Для распределённых систем используют message brokers:

// Spring Boot + RabbitMQ
@Configuration
public class RabbitConfig {
    public static final String USER_EVENTS_EXCHANGE = "user.events";
    public static final String USER_REGISTERED_QUEUE = "user.registered";
    
    @Bean
    public DirectExchange exchange() {
        return new DirectExchange(USER_EVENTS_EXCHANGE);
    }
    
    @Bean
    public Queue queue() {
        return new Queue(USER_REGISTERED_QUEUE);
    }
    
    @Bean
    public Binding binding(Queue queue, DirectExchange exchange) {
        return BindingBuilder.bind(queue)
            .to(exchange)
            .with("user.registered");
    }
}

@Service
public class UserService {
    private final RabbitTemplate rabbitTemplate;
    
    public void registerUser(String email) {
        // Публикация события в RabbitMQ
        rabbitTemplate.convertAndSend(
            RabbitConfig.USER_EVENTS_EXCHANGE,
            "user.registered",
            new UserRegisteredEvent(UUID.randomUUID().toString(), email)
        );
    }
}

@Service
public class EventListener {
    @RabbitListener(queues = RabbitConfig.USER_REGISTERED_QUEUE)
    public void onUserRegistered(UserRegisteredEvent event) {
        System.out.println("User registered: " + event.getEmail());
    }
}

Плюсы и минусы

Плюсы:

  • Слабая связанность: компоненты независимы
  • Масштабируемость: легко добавлять новых слушателей
  • Асинхронность: улучшает отзывчивость
  • Реактивность: система реагирует на события

Минусы:

  • Сложность отладки: трудно отследить поток выполнения
  • Глобальное состояние: события могут вызвать каскадные изменения
  • Порядок выполнения: не гарантирован порядок обработки
  • Overengineering: излишне для простых систем

Когда использовать

  • Микросервисная архитектура
  • Real-time системы (уведомления, чаты)
  • Системы с множеством асинхронных операций
  • Системы, требующие слабой связанности

Событийно-управляемая архитектура — мощный паттерн для создания гибких и масштабируемых систем.

Что такое событийно-управляемая архитектура? | PrepBro