Java Message Service – JMS

Her mesajlaşma uygulaması için konfigure edilen iki tip yönetim objesi vardır.
  1. Destinations
  2. Connection Factories
Destinations denilen yapılar mesajları almak, tutmak ve yönlendirmek için kullanılırlar. Queue ve Topic Destination’lar olmak üzere ikiye ayrılırlar.
  1. Queue Destination : Point-to-Point mesajlaşma protokolü
  2. Topic Destination : Yayınla-al mesajlaşma protokolü

İstemci Queue’ya erişebilecek bir Connection sınıfı üzerinden bu Queue’ya erişebilir. Yani direk erişemez. Queue’ya erişmek için bu Connection sınıfını kullanıp session oluşturulur. Session üzerinden Queue’ya bağlanılır. Bu bağlantı sınıfına “connection factory” denir. Connection Factory uygulama sunucusu üzerinde tanımlanır.

İstemci tarafı Queue’ya erişebilsin diye Connection Factory oluşturulur.

Connection factory’ler JMS API Client tarafından JMS API Destination’a bağlanmak için kullanılır. İki kategoriye ayrılırlar.

  1. Queue Connection Factories
  2. Topic Connection Factories

 

İstemcilerin Mesaj Göndermesi :

İstemcileri mesaj gönderen uygulamalar olarak düşünebilirsiniz. Gönderilen mesajlar senkron ya da asenkon olabilir. Yani mesaj gönderildikten sonra cevabın ne zaman döneceği belli olmayabilir. Senkron mesajlarda gönderilen mesajın cevabı beklenir.
1

Mesajlar :

Uygulamaya ait bilgileri sarmalamaya yarayan objelerdir. Mesajın 3 parçası vardır.
  1. Header : Mesajı tanımlamak ve yönlendirmek için bilgi barındırır.
  2. Properties : Mesajları sınıflandırmak için kullanılır. Isim/değer tutulur. Mesajlar özelliklerine göre filtrelenebilir.
  3. Body : Mesajın içeriği bulunur.
5 adet mesaj tipi vardır. Sunucudaki queue ya da topic yapılarına bu beş tipte mesajdan ihtiyaca göre bir tanesi gönderilebilir.
2

 

 

Point-to-point Mesajlaşma (Queue) :

Bir mesaj kuyruğu (queue), mesajların tamamı tükenene kadar saklar. Queue ve topic arasındaki en büyük fark, Queue yapısında tek bir mesaj kullanıcısının olmasıdır. Mesajı gönderen ve alan arasında zaman anlamında bir bağımlılık yoktur. Queue’ya gönderilen tüm mesajlar alıcının yaratılmasından önce bile gönderilmiş olsalar sonradan alınabilirler.
Bir tüketici kuyruktan bir mesajı aldıktan sonra aynı mesaj başka birisi tarafından kullanılamaz.
3

Publish/Subscribe Mesajlaşma (Topic) :

Bir Topic’in birden fazla kullanıcısı olabilir. Mesajı üreten istemci mesajları Topic’e gönderir. Topic mesajların tamamı kullanıcılara dağıtılana kadar hepsini saklar. Burada iki taraf arasında zaman bağımlılığı vardır. Mesaj alacak kişiler, Topic’e kayıt olmadan ya da inaktif durumdayken mesaj alamazlar.
4
EJB bileşenleri (entity, session, message-driven beans) ile mesaj göndermek mümkün olabilir. Yalnız JMS API’nin ihtiyaç duyduğu metotların yazılması gerekir.
Senkron mesaj kullanıcıları sunucuyu bloke edip bağladıkları için session, entity ve message-driven bean’ler ile senkron mesaj göndermek sakıncalıdır.
Message-driven bean’ler MessageListener interface’ini implement ederler. Yani asenkron mesajlaşma için kullanılırlar. MessageListener arayüzünde tanımı yapılmış onMessage() metodunu override ederler. Container’a MessageListener kullanıldığının bir şekilde söylenmesi gerekiyor. Bunu da message-driven bean’lerin başında @MessageDriven annotation‘ı ile ifade ediyoruz.
MDB’lerin local ya da remote interface’leri olmaz. MDB’ler Java EE bileşenleri ile direk olarak haberleşmezler. Önce mesajı queue ya da topic yapısına gönderirler. Container’lar mesajları göndermek için havuz kullanabilirler ki çoğu zaman kullanırlar.
Container MDB instance’ı yaratırken newInstance() adındaki metodu otomatik olarak çağırır. Instance yaratıldıkdan sonra çalışacak olan metot PostConstruct metodudur. (Bu metotları annotationlarla belirliyorduk.) Daha sonra Container beani havuza ekler. Bean daha sonra listener metodunun çağrılmasını bekler. Mesaj eklendikçe listener metodu çalışır.
  • MDB’ler public tanımlanır ve aynı diğer beanler gibi final ya da abstract olmaz.
  • Class tanımının başında @MessageDriven annotation’ı olur.
  • mappedName özelliği ile MDB uygulama sunucusunda tanımlanmış olan destination’lara JNDI ismiyle bağlanır.
  • finallize() metotları olmaz.
  • Bean içerisinde event handler metotları tanımlanabilir. Eskiden bu metotları override etmek zorunluydu şimdi bean instance’ı yaratılmadan önce ve sonra eventler oluşuyor. İstersek PostConstruct ve PreDestroy metotlarını yazabiliyoruz. Aynı diğer bean sınıflarındaki gibi herhangi bir isimde void bir metot tanımlanıyor. Bu metot parametre almıyor. Herhangi bir modifier alabiliyor ama uygulamaya özel exception fırlatmaması gerekiyor. Runtime exception’lar önemli değil. Tanımlarının başına da @PostConstruct ya da @PreDestroy yazıyoruz.
EJB’ler arasındaki haberleşmenin senkron olması gerekli değilse yani cevabını hemen beklemiyorsak asenkron haberleşmeyi kullanıyoruz.  Ne zaman okunacağı bizim için önemli olmadığında MDB kullanıyoruz. Mesajlarımızı bırakıyoruz bir ara okunuyor.

EJB – Enterprise Java Beans

İki farklı kurumda ya da iki farklı yerde çalışan projeler olduğunu düşünelim. Bu farklı yerlerdeki projeleri birbirleri ile nasıl haberleştireceğiz? İşte uzakta çalışan uygulamaları birbirleri ile haberleştirmek için teknolojiler geliştirilmiştir. Bunlardan biri web servisleri, bir diğeri RMI’dır. EJB ise Java dünyasında kullanılan bir diğer haberleşme teknolojisinin ismidir.

EJB çalışma mantığı :

Öncelikle amacımız istemci tarafından, sunucudaki EJB sınıfına erişmek. Bunun için istemci tarafında bir nesne oluşturulması gerekiyor. Oluşturulan nesnenin aynı isimdeki metodunu çağırmalıyız. O da gidip sunucudaki aynı isimdeki metodu çağıracak. İstemci tarafındaki EJB’ymiş gibi kullanılan nesneye proxy objesi adı veriliyor. Bu proxy objesini biz kendisi EJB’ymiş gibi kullanıyoruz. Uzaktan kullanılabilecek metot listesini içerisinde barındırıyor. Dolayısıyla istemci tarafında Remote interface’e ihtiyacımız var. Oluşturulan proxy objesinin tipi de bu remote interface tipinde oluyor.

Üç tane EJB bileşeni vardır :

1-      Session Beans

  • Stateless Session Beans
  • Stateful Session Beans

2-      Entity Beans

3-      Message Driven Beans

Önemli : EJB kullanabilmek için uygulama sunucusunun mutlaka EJB Container’ı desteklemesi gerekir.

Stateless bean’ler, her istemci için yaratılan nesnenin bir havuzda saklanarak ihtiyaç duyulduğunda herhangi bir tanesini kullanmamızı sağlayan yapılardır. Stateful bean’lerde ise yapı tam ters şekildedir. Her bir istemcinin yaptığı her istek için bir instance oluşturulur. Dolayısıyla performans açısından sunucunun hafızası işgal edilmiş olur.

Stateless kullandığımızda sınıf değişkeni (global değişken) kullanmıyoruz. Çünkü istemci, her session bean istediğinde aynı bean instance’ına erişemeyebiliyor. Birden fazla istemciden gelen istekler aynı session bean tarafından yanıtlanabiliyor. Performans anlamında çok işimize yarıyor. Tüm istemciler için tek bir ejb instance’ı yaratılıyor. Herkes aynı nesneyi kullanıyor. Burada bean tek bir istemciye özel bilgi saklamıyor. Birçok istemcinin isteği aynı bean instance’ı tarafından cevaplanabiliyor. Bu da performans artırımı demek.

Bir session bean sınıfının stateless ya da stateful olduğunu annotation kullanarak söylüyoruz.

Genelde bir EJB çağırıyorsak peşinden de bir veri tabanı çağrımı yapılır. Çoğu projede bir veri tabanı kullanılıyor. Veri tabanı kullanmak, veri tabanına istek göndermek sıkıntılı bir işlem. SQL sorgularımızın yazıldığı katmanı, Connection’ın alındığı katmanı doğru yazmak, connection’ı açtıktan sonra kapatmayı unutmamak, aynı fonksiyonda iki farklı connection almamak gibi sıkıntılar var.

Bunun için EJB tarafında veri tabanına erişimi de kolay bir hale getirmek için frameworkler yazılmış. Bu frameworkler sayesinde veri tabanına connection açma, kapama işlemleri ile uğraşmadan erişip sorgu çekebiliyoruz. O kısımlar hazır kodlarla hallediliyor.

Entity bean’lerin çıkışı da yine bu amaçla olmuş. Veri tabanındaki her bir tablo için bir sınıf yaratıyoruz. Bu sınıflara entity bean deniyor.

5 tablomuz varsa, 5 tane bean yazılıyor. Tabloların özellikleri, ilişkileri bu sınıfların içerisinde tanımlanıyor.

Tablolarla uğraşırken tabloya karşılık gelen sınıfları istiyoruz. Muhattap olarak sadece sınıfları alıyoruz. Objelerle uğraşıyoruz. Bunun dışında veri tabanı ile ilgilenmiyoruz.

Entity bean’ler veri tabanına bağlanacak ama hangisi hangi connection bilgisi ile? Bunu da XML dosyasında tutuyoruz.

Message-driven bean’ler asenkron mesajlaşma için kullanılırlar. EJB’ler arasındaki haberleşmenin senkron olması gerekli değilse yani cevabını hemen beklemiyorsak asenkron haberleşmeyi kullanıyoruz. Mesajlarımızı bırakıyoruz bir ara okunuyor. Mesajların ne zaman okunacağı belli değil. Örneğin e-mail attık, karşı tarafın ne zaman okuyacağı bizi ilgilendirmiyor.

JMS API dediğimiz mesajlaşma servisi bir çok sınıf ve interface barındıran bir yapıdır.

Uygulama sunucusunun JMS’i desteklemesi için bazı ayarların yine sunucu tarafında yapılması gerekir.