Java İle Jms Kullanarak Mesaj Kuyruğu Tabanlı İletişim Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

JMS ile çalışmaya başlamadan önce geliştirme ortamınızı doğru yapılandırmanız gerekir. JMS bir API olduğu için arka planda bir mesaj broker'ına ihtiyaç duyar.

  • JDK 21 veya üzeri bir sürüm.
  • Apache ActiveMQ Artemis veya benzeri bir JMS uyumlu broker.
  • Maven veya Gradle tabanlı bir Java projesi.
  • Bağımlılık yönetimi için jakarta.jms-api ve ilgili broker istemci kütüphaneleri.

Projenizin pom.xml dosyasına aşağıdaki bağımlılığı ekleyerek işe başlayabilirsiniz:


    jakarta.jms
    jakarta.jms-api
    3.1.0


    org.apache.activemq
    artemis-jms-client
    2.35.0

JMS Mimarisi ve Temel Kavramlar

JMS, iki ana iletişim modeli sunar: Point-to-Point (PTP) ve Publish/Subscribe (Pub/Sub). PTP modelinde bir mesaj tek bir alıcıya giderken, Pub/Sub modelinde bir konu (topic) üzerinden birden fazla aboneye iletilir.

Kavram Açıklama Kullanım Amacı
Queue Noktadan noktaya mesaj kuyruğu İş yükü dağıtımı (Load Balancing)
Topic Yayınla/Abone ol modeli Olay tabanlı bildirimler (Event Notification)
ConnectionFactory Broker bağlantısı oluşturma aracı Güvenli bağlantı yönetimi
Session Mesaj gönderim/alım bağlamı İşlem (Transaction) yönetimi

Adım Adım Mesaj Gönderici (Producer) Oluşturma

Mesaj gönderici, bir mesajı belirli bir kuyruğa (Queue) ileten bileşendir. Öncelikle bir ConnectionFactory oluşturmalı ve ardından oturumu başlatmalısınız.

import jakarta.jms.*;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;

public class MesajGonderici {
    public void mesajGonder(String metin) throws Exception {
        ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
        try (Connection connection = cf.createConnection();
             Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) {
            
            Queue queue = session.createQueue("testKuyrugu");
            MessageProducer producer = session.createProducer(queue);
            TextMessage message = session.createTextMessage(metin);
            
            producer.send(message);
            System.out.println("Mesaj gönderildi: " + metin);
        }
    }
}

Yukarıdaki kodda try-with-resources yapısı kullanılarak bağlantıların otomatik kapatılması sağlanmıştır. Bu, kaynak sızıntılarını (memory leak) önlemek için kritik bir uygulamadır.

Adım Adım Mesaj Alıcı (Consumer) Oluşturma

Mesaj alıcı, kuyruktaki mesajları dinler ve işler. Mesajları senkron veya asenkron olarak alabilirsiniz. Aşağıdaki örnekte asenkron bir dinleyici yapısı gösterilmiştir.

public class MesajAlici implements MessageListener {
    public void dinlemeyeBasla() throws Exception {
        ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
        Connection connection = cf.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        
        Queue queue = session.createQueue("testKuyrugu");
        MessageConsumer consumer = session.createConsumer(queue);
        consumer.setMessageListener(this);
        
        connection.start();
    }

    @Override
    public void onMessage(Message message) {
        try {
            if (message instanceof TextMessage textMessage) {
                System.out.println("Alınan mesaj: " + textMessage.getText());
            }
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

MessageListener arayüzü, mesaj geldiğinde tetiklenen onMessage metodunu zorunlu kılar. Bu yöntem, uygulamanızın sürekli olarak mesajları beklemesini ve geldiklerinde işlem yapmasını sağlar.

JMS Mesajlaşmada İşlem (Transaction) Yönetimi

Mesajların kaybolmaması veya mükerrer işlenmemesi için işlemler (transactions) kullanılır. Bir mesajın başarıyla işlenmesi için session.commit() çağrılmalıdır.

Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
try {
    // Mesaj işlemleri
    producer.send(message);
    session.commit();
} catch (Exception e) {
    session.rollback();
}

İşlem yönetimi, hata durumunda mesajın kuyruğa geri dönmesini sağlar. Bu, veri tutarlılığı için vazgeçilmez bir mekanizmadır.

Kritik Güvenlik Uyarısı: Üretim ortamlarında (production) mesaj broker'ına bağlantı kurarken mutlaka kullanıcı adı ve şifre kimlik doğrulaması kullanın. Asla varsayılan (default) kimlik bilgilerini değiştirmeden kullanmayın ve bağlantılarınızı SSL/TLS ile şifreleyin.

Sıkça Sorulan Sorular

JMS ile AMQP arasındaki fark nedir?

JMS, Java dünyasına özel bir API standardıdır. AMQP (Advanced Message Queuing Protocol) ise dil bağımsız, ağ seviyesinde bir protokoldür. JMS, AMQP destekleyen broker'lar ile de çalışabilir.

Mesaj kuyruğu dolarsa ne olur?

Kuyruk dolduğunda broker'ın yapılandırmasına bağlı olarak mesajlar reddedilebilir (producer block) veya en eski mesajlar silinerek yer açılabilir. Bu durumu izlemek için broker metriklerini takip etmelisiniz.

Asenkron mesajlaşmanın avantajı nedir?

Sistemler arasındaki bağımlılığı (coupling) azaltır. Gönderici, alıcının o an müsait olup olmadığını bilmek zorunda değildir; mesaj broker'da güvenle saklanır.

JMS yerine neden Kafka kullanmalıyım?

Kafka, çok yüksek hacimli veriler ve olay akışı (event streaming) için optimize edilmiştir. JMS ise daha çok kurumsal iş süreçleri ve geleneksel mesajlaşma ihtiyaçları için idealdir.

Mesaj kaybını nasıl önlerim?

Mesajları "Persistent" (kalıcı) olarak işaretleyin ve işlem yönetimini (transaction) düzgün bir şekilde yapılandırın.

JMS Uygulamalarında Performans Optimizasyonu

Mesaj kuyruğu tabanlı sistemlerde yüksek trafik altında performans darboğazları yaşanabilir. JMS uygulamalarınızın ölçeklenebilirliğini artırmak için aşağıdaki stratejileri göz önünde bulundurmalısınız:

  • Connection Pooling: Bağlantı nesneleri (Connection) oluşturmak maliyetli bir işlemdir. PooledConnectionFactory kullanarak bağlantıları yeniden kullanın.
  • Batch Processing: Çok sayıda küçük mesaj göndermek yerine, bunları gruplandırarak tek bir işlem (transaction) içerisinde göndermek ağ trafiğini azaltır.
  • Asenkron Gönderim: CompletionListener kullanarak mesajın kuyruğa ulaşıp ulaşmadığını ana iş parçacığını (main thread) bloke etmeden takip edin.

Performans İçin Asenkron Gönderim Örneği

MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage("Yüksek performanslı veri");

producer.send(message, new CompletionListener() {
    @Override
    public void onCompletion(Message message) {
        System.out.println("Mesaj başarıyla iletildi.");
    }

    @Override
    public void onException(Message message, Exception e) {
        System.err.println("Mesaj iletim hatası: " + e.getMessage());
    }
});

JMS Uygulamalarında Hata Ayıklama ve İzlenebilirlik

Dağıtık sistemlerde bir mesajın kaybolması veya işlenememesi durumunda sorunun kaynağını bulmak zordur. İzlenebilirlik (observability) sağlamak için şu yöntemleri uygulayın:

  1. Message ID ve Correlation ID: Her mesaj için benzersiz bir JMSCorrelationID atayın. Bu, bir isteğin hangi yanıtla eşleştiğini takip etmenizi sağlar.
  2. Dead Letter Queue (DLQ): İşlenemeyen mesajları otomatik olarak bir "Ölü Mektup Kuyruğu"na yönlendirin. Bu, ana kuyruğun tıkanmasını engeller.
  3. Logging: Mesajın kuyruğa giriş ve çıkış anlarını, işlem süresiyle birlikte loglayın.

DLQ Yapılandırması ve İzleme

Çoğu JMS sağlayıcısı (ActiveMQ, Artemis vb.), hata alan mesajları belirli bir deneme sayısından sonra DLQ'ya taşır. Kod tarafında bu mesajları analiz etmek için şu yapıyı kullanabilirsiniz:

// Hatalı mesajları dinleyen özel bir Consumer
MessageConsumer dlqConsumer = session.createConsumer(session.createQueue("DLQ.MainQueue"));

dlqConsumer.setMessageListener(message -> {
    try {
        String originalId = message.getStringProperty("OriginalMessageID");
        System.err.println("İşlenemeyen mesaj tespit edildi. ID: " + originalId);
        // Burada veritabanına loglama veya manuel müdahale mekanizması tetiklenebilir
    } catch (JMSException e) {
        e.printStackTrace();
    }
});
İpucu: Üretim ortamında mesajlarınızı her zaman JMSDeliveryMode.PERSISTENT modunda gönderin. Bu, mesajın broker çöktüğünde diskte saklanmasını ve kaybolmamasını garanti eder.

Sonuç

Java ile JMS kullanarak mesaj kuyruğu tabanlı iletişim kurmak, sistemlerinizin esnekliğini ve dayanıklılığını artırır. Bu rehberde, bağlantı kurma, mesaj gönderme, alma ve işlem yönetimi gibi temel adımları inceledik. Bir sonraki adım olarak, Spring Boot ile JMS entegrasyonu (JmsTemplate kullanımı) konusunu inceleyerek kodunuzu çok daha sade ve yönetilebilir hale getirebilirsiniz. Unutmayın, mesaj tabanlı mimarilerde hata yönetimi ve izlenebilirlik, kodun kendisi kadar önemlidir.

Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamına almadan önce kendi güvenlik protokollerinizi ve hata yönetimi stratejilerinizi uyguladığınızdan emin olun.
Bu yazıya tepkinizi paylaşın:
Mert Demir

Teknik konuları sadeleştirerek geniş kitlelere ulaştırma konusunda tutkuluyum. Ev işleri, bakım ve organizasyon temalı rehberlerimde kaliteyi ön planda tutuyorum.

Yorumlar (0)

Yorum Yaz