← Назад к вопросам
Что такое событийно-управляемая архитектура?
2.0 Middle🔥 121 комментариев
#SOLID и паттерны проектирования#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Событийно-управляемая архитектура
Событийно-управляемая архитектура (Event-Driven Architecture) — это парадигма проектирования систем, где компоненты взаимодействуют друг с другом посредством обмена событиями. Вместо прямых вызовов методов (синхронная связь), компоненты создают события, на которые подписываются другие части системы.
Основные компоненты
- Event Source — компонент, создающий события
- Event Handler — компонент, обрабатывающий события
- Event Channel — способ доставки события (очередь, шина, тема)
- 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 системы (уведомления, чаты)
- Системы с множеством асинхронных операций
- Системы, требующие слабой связанности
Событийно-управляемая архитектура — мощный паттерн для создания гибких и масштабируемых систем.