Saturday, October 30, 2004

Message Driven Beans

J2EE standartının parçası olan JMS hakkında, daha önceki MDB yazımızda MQSeries çerçevesinde örnekler ile bahsetmiştik. Not olarak düşmek gerekir ki, piyasada olan diğer birçok mesaj kuyruğundan sadece bir tanesidir. Ayrıca Java piyasasındaki tüm ürünler artık JMS standartını destemektedir, bu yüzden biri için yazılan kod diğerine taşınabilir hâlde olmaktadır. Diğer ürünler arasında JBossMQ ve FioranoMQ gibi paketleri sayabiliriz.

Bu yazımızda, bir ileti kuyruğundan mesaj almanın "pür JMS" dışındaki alternatif yolları göstereceğiz. Bu alternatif yol Mesaj Tetikli Bean'dir, yâni Message Driven Beans (MDB). (Tabii ki MDB'ler alt süreçlerinde JMS kullanmaktadırlar, ama JMS arayüzlerini büyük miktarda programcıdan saklarlar).

MDB'ler Nedir?

MDB'ler aslında J2EE şemsiyesinin altıdaki diğer akrabaları EJB'ler gibi bir EJB sayılıyorlar. Hakikaten de MDB kodları yazarken ve paketleyip sonuç ortamına gönderirken (deploy), bu benzerliği daha rahat göreceksiniz. Fakat kodlama ve anlambilimsel olarak MDB kavramı Session Bean'lerden biraz değişiktir.

Bu değişikliklerden en önemlisi, bir MDB'nin ne zaman tetiklendiği yâni kullanılma anıdır. Bu an, MDB'nin gözlediği kuyruğa bir mesaj konduğu andır.

Bir MDB, her zaman bir kuyruk üzerinde bekçilik yapar. Ayar bağlamında, yazdığınız her MDB class tipi için bir ayartanım dosyasında o MDB için bir queue ismi tanımlamanız gerekir. Bunu yaptıktan sonra ve uygulama servisiniz MDB'niz ile koşmaya başladığında, artık o kuytuğa atılan her JMS mesajı, MDB'nin onMessage metotunu tetikleyecektir.


public void onMessage(javax.jms.Message message) {
...
}

Gördüğünüz gibi onMessage metotuna bir JMS message nesnesi parametre olarak geçilmiş. Ne kadar rahat! Programcının bu noktada tek yapması gereken bu mesajın içeriğine bakarak bazı kararlar alması ve diğer sistem birimlerine erişerek kodunu tamamlamasıdir.

Eğer aynı işi pür JMS kullanan şekilde yazsaydık, bir döngü içinde filan kuyruktan mesaj bekleyen kodlar yazmamız gerekecekti. karşılaştırırsanız, MDB yolunun ne kadar rahat olduğu belli olmaktadır.

Bir diğer fark ise, MDB'lerin, diğer EJB'lerin aksine HomeInterface ve RemoteInterface gibi garabetlere gerek bırakmamasıdır. Zaten bu tür kullanım EJB 3.0'da da standarttan atılmıştır. Hepimize kutlu olsun!

Şimdi MDB'lere dönelim.

Koşturma Anı

Koşturma sırasında her tek JMS mesajı, tek bir MDB tarafından servislenecektir. Bu mesaj muamele edildikten sonra, yâni MDB'nin onMessage metotu bittikten sonra, MDB'nin de işi bitmiş demektir. İşte bu her mesaj için gereken MDB'yi, ölçekleme açısından bir havuzda tutabilirsiniz. MDB'lerinizin başlaması (new metotu) zaman alan bir işlem ise, her mesaj için bu zamanı ziyan etmek yerine önceden başlatılmış MDB'lerin bir mesajı servislemesi daha hızlı olacaktır. Tüm modern uygulama servisleri bu tür bir ayarı desteklemektedir. Bu durumda bir mesajı servisleyen ve işi biten MDB'ler, geldikleri havuza dönerler.

JBossMQ

Şimdi gelelim örneğimize. Ekteki kodlarda JBoss üzerinde çalışan bir MDB örneği göreceksiniz. Bu örneğin gerçek dünya uygulamasına daha yakın olması için, paketin içine MDB'den Hibernate kullanarak veri tabanına erişen kodlar ve tanımlar da eklenmiştir.

Zip dosyasını açtıktan sonra yapmanız gereken, önce lib dizinini gerekli jarlar ile doldurmak (bunun için gereken jarları sitemizden bulabilirsiniz), ve sonra build.properties içindeki jboss.home adlı değişkeni JBOSS paketini kurduğunuz dizini gösterecek şekilde değiştirmektir.

Bunu yaptıktan sonra, önce "ant lokal-jboss-hazirla" ve sonra sadece "ant" ile MDB kodlarını derleyip, JBOSS altındaki JBOSS/server/default/deploy/ dizinine göndermeniz mümkün olacaktır.

JBOSS, deploy dizinleri altındaki her yeni EAR'i bir J2EE uygulaması olarak addettiği için, bu dosyayı açıp kendi içinde onu koşturmaya başlayacaktır.

Ant betiğinin bir diğer hissettirmeden yaptığı işlem, "ant lokal-jboss-hazirla" sırasında JBossMQ'da bir queue tanımlamasıdır. JBoss'ta queue tanımlamak için sonu "-servis.xml" ile biten bir dosya içinde şu bir tür tanım koymaktan ibarettir.



<?xml version="1.0" encoding="UTF-8"?>

<server>

<mbean code="org.jboss.mq.server.jmx.Queue"
name="jboss.mq.destination:service=Queue,name=OrnekQueue">
<depends optional-attribute-name="DestinationManager">
jboss.mq:service=DestinationManager</depends>
</mbean>

</server>





Bu -servis.xml dosyası, deploy dizini altına konduğu zaman JBoss koşturma anında -servis.xml ile biten tüm dosyaları başlatmaya çalışacağı için, burada tanımlı olan queue'muzda başlamış olacaktır.

Bu tanım dosyası içinde de gördüğümüz gibi OrnekQueue adında bir queue tanımlanmıştır. "Hangi queue'yu hangi MDB'nin beklediği" ise, dd/ dizini altıdaki jboss.xml içinde tanımlıdır. Bunun örneği de aşağıdaki gibidir.



<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE jboss PUBLIC
"-//JBoss//DTD JBOSS 3.2//EN"
"http://www.jboss.org/j2ee/dtd/jboss_3_2.dtd">

<jboss>
<enterprise-beans>
<message-driven>
<ejb-name>OrnekMDB</ejb-name>
<destination-jndi-name>queue/OrnekQueue</destination-jndi-name>
</message-driven>
</enterprise-beans>
</jboss>





jboss.xml dosyası, servis dosyaları aksine EAR paketi içine konulması gereken bir dosyadır. J2EE standartına göre bu böyledir. Ant betiği bunları da otomatik olarak yapacaktır.

Kod derlenip EAR olarak gönderildikten sonra, geriye kalan JBOSS'u başlatmaktan ibarettir. Test etmek için, herşey başladıktan sonra "ant test-integ-single -Dtest=MdbTestUnit.class" komutu ile queue'ya bir mesaj göndermeyi test edebilirsiniz. OrnekQueue üzerine gidecek mesaj, OrnekMDB tarafından okunacak, ve bu MDB içinde Hibernate üzerinden veri tabanındaki bir tablo okunmaya çalışılacaktır.

Diğer Konular

Sıralama

Ölçekleme bağlamında bir mevzudan daha bahis etmek gerekiyor. Eğer elimizde bir MDB havuzu var ise, ve queue'ya çok hızlı bir şekilde bir sürü mesaj geliyor ise, aynı mesajı birden fazla MDB alamaz mı?

Hayır, bu imkansızdır. MDB'lerin queue'dan mesaj okuması, aslında bir mesaj kapma ruhunda ilerleyen bir işlemdir. Bir MDB'ye verilen mesaj, sadece o MDB'ye verilir, ve o anda queue'dan çıkartılır. Yâni MDB o mesaji kapmış olur.

Bu ufak detayı da, aslında, MDB bazlı sisteminizi ölçeklemek için bir mihenk taşı olarak kullanabilirsiniz. Öyle ki, üzerine mesaj konan queue, mesela ayrı bir JBOSS JVM'i içinde olabilir, ve okuyan MDB'ler birden fazla ve yine ayrı JBOSS JVM'leri üzerinden, uzaktaki bu queue'ya erişiyor olurlar, ve mesajları kaparlar. En hafif yüklü olan JBOSS process'inin MDB'leri muhtemelen bir sonraki mesaji kapacağı için, kendiliğinden bir yük dengeleme işlemi (load balancing) yapılmış olur. Bu yazıdaki örneğimizde uzak (remote) bir queue'ya bağlanmayı göstermiyoruz, fakat İnternet kaynaklarından bu tekniği uygulamaya geçirebilirsiniz.

JBossMQ Nerede?

JBossMQ, JBOSS uygulama servisinin bir parçasıdır. Yâni başka hiçbir ek program kurmanız gerekmiyor. JBossMQ, belli bir port üzerinden servis yapan diğer JBoss altbirimleri gibi JBOSS'un bir parçasıdır, ve eğer servisi tanımlı ise (ki JBOSS/server/default tanımı bunu yapmaktadır), run.sh ile JBOSS'u başlattığınızda işleme konacaktır. Yâni, MQSeries ya da FioranoMQ gibi "startQueue.sh" gibi bir betiği aramanıza gerek yok! JBoss'un olağan ayarları size bir Queue idare sistemi bedavadan verecektir.

İyi calışmalar,

Kaynaklar


* JBOSS Sitesi
* Uzak Bir Queue'ye Erişmek
* Örnek Kodlar #1: Gösterilen teknikler, JBOSS'ta MDB tanımı, bu MDB'ye erişilmesi, ve MDB içinden Hibernate kullanarak DB'den veri alınması.
* Örnek Kodlar #2: Üstteki test, artı bir Servlet.

No comments: