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

Какие решения использовал из категории message-driven

2.0 Middle🔥 141 комментариев
#Основы Java

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

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

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

Ответ

Message-Driven архитектура в Java

Message-Driven архитектура — это асинхронное взаимодействие между компонентами через сообщения. Это критически важно для микросервисов, распределённых систем и высоконагруженных приложений.

1. RabbitMQ (самая популярная)

// Spring AMQP - работа с RabbitMQ
@Configuration
public class RabbitMQConfig {
    public static final String EXCHANGE_NAME = "orders_exchange";
    public static final String QUEUE_NAME = "orders_queue";
    public static final String ROUTING_KEY = "order.*";
    
    @Bean
    public DirectExchange exchange() {
        return new DirectExchange(EXCHANGE_NAME, true, false);
    }
    
    @Bean
    public Queue queue() {
        return new Queue(QUEUE_NAME, true);
    }
}

// Producer (отправитель сообщений)
@Service
public class OrderProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendOrder(Order order) {
        rabbitTemplate.convertAndSend(
            RabbitMQConfig.EXCHANGE_NAME,
            "order.created",
            order
        );
    }
}

// Consumer (получатель сообщений)
@Service
public class OrderConsumer {
    @RabbitListener(queues = RabbitMQConfig.QUEUE_NAME)
    public void processOrder(Order order) {
        System.out.println("Processing order: " + order.getId());
    }
}

2. Apache Kafka (для больших объёмов)

// Spring Kafka configuration
@Configuration
public class KafkaConfig {
    public static final String TOPIC = "orders-topic";
}

// Producer (отправитель)
@Service
public class KafkaOrderProducer {
    @Autowired
    private KafkaTemplate<String, Order> kafkaTemplate;
    
    public void sendOrder(Order order) {
        kafkaTemplate.send(KafkaConfig.TOPIC, order.getId(), order);
    }
}

// Consumer (получатель)
@Service
public class KafkaOrderConsumer {
    @KafkaListener(topics = KafkaConfig.TOPIC, groupId = "order-service")
    public void consume(Order order) {
        System.out.println("Received order: " + order.getId());
    }
}

3. JMS (Java Message Service)

// Для ActiveMQ, HornetQ
@Configuration
public class JmsConfig {
    @Bean
    public Queue orderQueue() {
        return new ActiveMQQueue("order-queue");
    }
}

// Producer
@Service
public class JmsOrderProducer {
    @Autowired
    private JmsTemplate jmsTemplate;
    
    public void sendOrder(Order order) {
        jmsTemplate.convertAndSend("order-queue", order);
    }
}

// Consumer
@Service
public class JmsOrderConsumer {
    @JmsListener(destination = "order-queue")
    public void processOrder(Order order) {
        System.out.println("JMS Order processed: " + order.getId());
    }
}

4. Spring Cloud Stream (абстракция над сообщающими системами)

// Интерфейс для binding
public interface OrderBinding {
    String ORDER_OUTPUT = "order-output";
    String ORDER_INPUT = "order-input";
    
    @Output(ORDER_OUTPUT)
    MessageChannel orderOutput();
    
    @Input(ORDER_INPUT)
    SubscribableChannel orderInput();
}

// Producer
@Service
@EnableBinding(OrderBinding.class)
public class StreamOrderProducer {
    @Autowired
    private OrderBinding binding;
    
    public void sendOrder(Order order) {
        binding.orderOutput().send(
            MessageBuilder.withPayload(order).build()
        );
    }
}

// Consumer
@Service
@EnableBinding(OrderBinding.class)
public class StreamOrderConsumer {
    @StreamListener(OrderBinding.ORDER_INPUT)
    public void handleOrder(Order order) {
        System.out.println("Stream order: " + order.getId());
    }
}

5. WebSockets (для real-time коммуникации)

// Spring WebSocket Configuration
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new OrderWebSocketHandler(), "/ws/orders")
            .setAllowedOrigins("*");
    }
}

// WebSocket Handler
@Component
public class OrderWebSocketHandler extends TextWebSocketHandler {
    private static final Set<WebSocketSession> sessions = new CopyOnWriteArraySet<>();
    
    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        sessions.add(session);
    }
    
    public void notifyOrderUpdate(Order order) {
        for (WebSocketSession session : sessions) {
            try {
                session.sendMessage(
                    new TextMessage(objectMapper.writeValueAsString(order))
                );
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Сравнение решений

РешениеЗна́я о РТМасштабИспользование
RabbitMQ~100msСреднийМикросервисы, задачи
KafkaВысокая пропускная способностьБольшойStreaming, big data
JMSУниверсальныйСреднийLegacy системы
Spring Cloud StreamАбстракцияЛюбойFramework-agnostic
WebSocketsReal-timeСреднийКлиент-сервер

Практический сценарий

// Event-driven микросервис архитектура
public class OrderService {
    @Autowired
    private OrderProducer orderProducer;
    
    @Transactional
    public void createOrder(Order order) {
        // 1. Сохраняем в БД
        orderRepository.save(order);
        
        // 2. Отправляем событие асинхронно
        orderProducer.sendOrderCreatedEvent(order);
        // Не ждём обработки - сразу возвращаемся
    }
}

// Отдельный микросервис обработает событие
@Service
public class NotificationService {
    @RabbitListener(queues = "order-created-queue")
    public void onOrderCreated(Order order) {
        emailService.sendOrderConfirmation(order);
    }
}

// Ещё один микросервис
@Service
public class AnalyticsService {
    @RabbitListener(queues = "order-created-queue")
    public void onOrderCreated(Order order) {
        analyticsRepository.logOrderEvent(order);
    }
}

Типичная ошибка

// ❌ ПЛОХО: синхронное взаимодействие (blocking)
public void createOrder(Order order) {
    orderRepository.save(order);
    notificationService.sendEmail(order);  // Ждём ответа!
    analyticsService.logEvent(order);      // Ждём ответа!
}

// ✅ ПРАВИЛЬНО: асинхронное (message-driven)
public void createOrder(Order order) {
    orderRepository.save(order);
    messageProducer.send(new OrderCreatedEvent(order));
    // Не ждём - сразу вернулись
}

Что спрашивают на собеседовании

  • RabbitMQ vs Kafka: когда что использовать
  • Producer-Consumer паттерн: как отправлять и получать сообщения
  • Message ordering: гарантии доставки
  • Dead letter queue: обработка ошибок
  • Event sourcing: сохранение всех событий
  • Spring AMQP vs Spring Kafka: различия в API
  • Масштабирование: как масштабировать потребителей
Какие решения использовал из категории message-driven | PrepBro