Dağıtık uygulama geliştirmek, geliştirilen uygulamayı çalışır halde tutmak, izlemek ve hata ayıklamak zordur. Java EE 6 ve 7 platformu bu zorluğun üstesinden gelmek için çeşitli çözümler sunmaktadır. Java EE 5 ile birlikte programlama modelinde önemli bazı değişiklikler gerçekleşmiştir. Programlama modelinin ve mimarinin temel özellikleri aşağıdaki gibi sıralanabilir:
- Bileşen Tabanlı Programlama
- Sıradan Java Sınıflarının Kullanımı
- Betimsel Programlama
Sınıflar tek bir sorumluluğa sahip ya da tek bir konuda uzman olacak şekilde tasarlanır. Böylelikle sınıflar sadece uzmanlık alanlarında diğer sınıflara hizmet verirler. Bazen bir sınıf uzmanlığı dışında bir iş yapması gerektiğinde, konunun uzmanı sınıf hangisi ise ondan hizmet alır ve isteği bu sınıfa ihale eder. Bu şekilde sınıflar arasında hizmet alma-verme ilişkisi doğar. Bu ilişkinin gevşek bağlı olacak şekilde düzenlenmesi, yazılımdaki değişimin yönetilebilmesi için çok önemlidir. Bunun için hizmet alan ve hizmet veren sınıf arasına bir arayüz yerleştirilir. Bu arayüz bir sözleşme işlevi görür. Sınıflar biri birlerinden bu sözleşmeye uygun olarak hizmet alır ve hizmet verirler. Java programlama dilinde nesneler bu şekilde biri birlerinden hizmet alırlarken, istekler senkron olarak karşılanır. Hizmet alan sınıf cevap gelene kadar bekler. Ancak çok-lifli (=multi-threaded) programlama ile asenkron bir yapı kurulabilir. Hizmet alan ve hizmet veren sınıf arasında asenkron bir yapı kurmanın bir başka yöntemi araya bir mesajlaşma sistemi yerleştirmektir. Hizmet alan nesne isteğini bir mesaj olarak mesajlaşma sistemine iletir ve yoluna devam eder. Hizmet veren nesne mesajı alır ve işler.
Message-Driven Bean (MDB) kullanmak için JMS (Java Messaging System) sunucusuna ihtiyaç duyulur. İstemci isteğini bir mesaj olarak kuyruğa yerleştirir ve yoluna devam eder. Hizmet veren sınıf, MDB, vakit buldukça kendisine gelen mesajları alır ve işler. Eğer işlem mili saniye mertebesinde sürelerde tamamlanabilecek sürelerde ise Session Bean, saniye, dakika mertebesinde ya da daha da uzun soluklu ise MDB olarak gerçeklenir. Genellikle uygulama sunucuları üzerinde birer JMS sistemi bulunur. İstenirse JMS sunucusu ayrı olarak da kurulabilir. JMS üzerinden hizmet alan ve veren bileşenler böylelikle fiziksel olarak farklı makinalarda olabilir. Üstelik hizmet veren bileşen, Java EE'de bu MDB olacaktır, henüz ayakta olmasa bile sorun çıkmaz. Bir süre sonra MDB çalışmaya başlar ve kuyrukta biriken mesajları alarak gereğini yerine getirmeye ve iş mantığını çalıştırmaya başlar.
JMS üzerinden hem tasarımsal hem de fiziksel olarak gevşek bağlı yapılar oluşturulabilir. JMS tabanlı çözümün en önemli yitimi, asenkron olarak iletilen isteğin sonucu için hazırda bir çözümün olmayışıdır. İşlemin sonucunu veritabanı üzerinden ya da başka bir mesaj kuyruğu üzerinden alınabileceği çözümler kurulabilse de bu mimariyi biraz karmaşık hale getirecektir.
Java EE 6 ile birlikte yeni bir bileşen modelimiz daha var: CDI (Contexts and Dependency Injection) Bean. CDI en temelde hizmet alan ve veren bileşenler arasındaki bağımlılıkları yöneten bir çatı sunuyor. Tıpkı Spring, Guice, JBoss Seam gibi. Bunun dışında ilgiye dayalı programlama, olay temelli programlama ve dekoratör tasarım kalıbı gibi çözümlere hızlı bir şekilde ulaşmamızı sağlar. CDI'nın şartnamesine bu bağlantıdan erişebilirsiniz. CDI Java EE'deki diğer tüm API'lerle ve onların bileşenleriyle tümleşik çalışacak şekilde tasarlanmıştır.
Bu yazıda CDI çatısının olay temelli programlama çözümünü inceleyeceğiz. İncelememizi Wildfly üzerinde çalışan bir Java EE 7 uygulaması üzerinde gerçekleştireceğiz. Öncelikle bir olay sınıfı tasarlamamız gerekiyor. Olay sınıfının hiç bir özelliği bulunmayan, yalın bir Java sınıfı olması istenir. Sadece özniteliklerden oluşan ve durumu değiştirilemez bir sınıf olması tercih edilir. Bu anlamda aykırı durumlar için tasarladığımız Exception sınıfları ile benzerlik gösterir. Exception sınıflarının da sadece hatayı açıklayan öznitelikler içermesini isteriz. Exception sınıfının kesinlikle hatayı çözmeye çalışan metodlar içermemelidir. Örnek uygulamamızda 1000 liranın üzerindeki para akışlarının bir web sayfasından izlenmesi sağlanıyor. Para transferi iş mantığı katmanında bir CDI bileşeni tarafından gerçekleniyor. Önce olay sınıfına bir bakalım:
Şimdi olayı yayınlayacak, iş mantığı katmanındaki bileşene ve arayüzüne göz atalım:
AccountService.java:
SimpleAccountService.java:
package com.example.service.impl;
Olayı yayınlayacak bileşenin, basitçe Event
- JMS ile kümeleme yapılabilir. CDI ise sadece aynı Java Sanal Makinasındaki bileşenler için yerel bir çözüm üretir.
- JMS mesajların alındığını garanti eder. Hata oluşursa tekrar deneyebilir.
- JMS sunucuları dağıtık atomik işlemlerde yer alabilir.
Websocket standardı HTML 5 ile gelen ve web tarayıcısı ile sunucu arasında tam çift yönlü (=Full Dublex) haberleşme sağlayan yeni bir protokoldür. Bu protokol yardımı ile istemci istekte bulunmasa bile sunucu web tarayıcısına veri gönderebilir. Bu örnek uygulamada, olay yaratıldığında, bu olayı sunucudan tarayıcılara göndererek, oturum açarak sunucuya bağlı bulunan kullanıcıları anında bilgilendirmek istiyoruz. sendEvent(@Observes OverdraftEvent event) metodunun imzasına baktığımızda önce olay tipinde (OverdraftEvent) bir parametre aldığını görüyoruz. Bu parametreye ayrıca @Observes notunun düşüldüğünü görüyoruz. Bu şekilde sendEvent metodunun OverdraftEvent olaylarına abone olmasını sağladık. Dergi aboneliğine benzer şekilde, derginin her yeni sayısı çıktığında tüm abonelere ulaştırılır. Her bir olay fırlatıldığında bu olayın gözlemcilerine haber verilir. Uygulamanın kullanımına ve çalışmasına ilişkin örnek bir çıktı aşağıdaki şekilde verilmiştir:
Tüm uygulamanın kaynak koduna bu bağlantıdan ulaşabilirsiniz. CDI ve Java EE 7 ile ilgili daha detaylı bilgi edinmek için "Developing Enterprise Applications on Java EE 7" ve "Contexts and Dependency Injection (CDI)" eğitimlerinin içeriklerini inceleyebilirsiniz.