Spring ve Hazelcast

Hazelcast uzun zamandır kullanmak istediğim fakat bir türlü denemeye fırsat bulamadığım bir kütüphane. Hazelcast veri dağıtımı için geliştirilmiş bir kütüphanedir. Processler arası iletişimde kullanabileceğiniz gibi verinizi tek bir lokasyon üzerinde cache’lemek için de kullanabilirsiniz.

Hazelcast ile denemeler yaparken benim beklentim öyle fazla bir şey değildi açıkçası. Veritabanında tuttuğum verileri bir map üzerinden bellekte tutmak ve bu bellek alanına farklı java processlerinden erişmek istiyordum. Aynı zamanda uygulamamı scale ettiğimde de sorun çıkarmayacak bir kütüphaneye ihtiyacım vardı.

Bu tutorial çerçevesinde de buna benzer bir işlevin hazelcast ile nasıl yapılacağını anlatmaya çalışacağım. En doğru kullanım şekli bu mudur? Başka hangi kullanım şekilleri olabilir? gibi konulardan ziyade, dağıtık bir veri yapısını nasıl oluşturur ve yönetirimin üzerinde durmaya çalışacağım. Bunu yaparken de tabiki de Spring ile entegre çalışacağım.spring_hazelcast

Kısaca bu tutorial çerçevesinde aşağıdaki sorunların çözümlerine değinmeye çalışacağım.

  • Hazelcast ile bellekte bir map’i nasıl farklı uygulamalardan çağırabilecek şekilde ayağa kaldırırım?
  • Bu map alanını lazy şekilde doldurmak istiyorum. Yani, tutorial çerçevesinde basit bir User nesnesi üzerinden devam edeceğim. Bu user nesnesinin 3 temel alanı olacak. Kullanıcı adı, parola ve email… Map üzerinde kullanıcı adı üzerinden tutulmasını istiyorum. Fakat doğrudan çekilmesini değil ben talep ettikçe map’in dolmasını istiyorum.
  • Veritabanından (yani Persistence Store) veriyi nasıl çekeceğim tamamen benim sorumluluğumda olmalı. Tablo yapımı kendim belirleyebilmeliyim. Tablodan nasıl çekeceğime kendim karar verebilmeliyim. Örneğin tutorial çerçevesinde ben SpringData kullanacağım ama istenildiğinde JPA ya da başka bişey kullanabilsin.
  • Yeni bir veri oluşturduğumda ben bu yeni veriyi map’a atayım. Belirli bir aralıkta (örneğin 60sn) bu veri, veritabanına otomatik kaydedilsin.
  • Map üzerinde kayıtlı User nesnesinin bir değerini (örneğin email) değiştirdiğimde belirli bir süre sonra bu değişiklik veritabanına da yansısın. (örneğin yine 60sn)

Yer yer başka sebeplerle farklı hazelcast alternatifleri (ehcache, Memcached etc) de kullanmış biri olarak söyleyebilirim ki hazelcast’i kullanmaya başlamak diğerlerine nazaran oldukça kolay.

Projenin Yaratılması

Şimdi öncelikle projemizi oluşturalım. Basit bir projemiz olacak. Temel olarak sadece bir User nesnemiz olacak. Tanımlayacağımız SpringData (JPA) modülü üzerinden User nesnesinde CRUD(Create, Read, Update ve Delete) işlemleri yapılabilecek. Aynı zamanda bir de REST servisi ayağa kaldıracağız cache’imiz üzerinden okuma ve yazma yapabildiğmizi spring-initgörebilelim. Tüm bunları hızlıca ve vakit almadan yapabilmek için SpringBoot kullanacağım. Intellij’de sağolsun SpringBoot’u desteklediğinden (ben 4.1.1 versiyonunu kullanıyorum) işim daha da kolaylaşıyor.  Şöyle düşünün SpringBoot sayesinde, 5 java sınıfı ve 0 xml (pom.xml’i saymıyorum tabiki de) ile tutorialı sonlandıracağız.

Her ne kadar intellij üzerinden anlatacak olsamda aynı adımları https://start.spring.io/ adresinden de yapabilirsiniz.

Intellij üzerinden yeni bir proje yaratıyoruz fakat proje türü olarak Spring Initializr seçiyoruz. Bu bizi bir takım adımlardan götürecek ve uygulamamızı tamamlamış olacağız. Intellij’de bu adımları zaten https://start.spring.io/ adresinden temin ediyor.

SpringInitializr’ı seçtikten sonra next dediğimizde, bizi proje ile ilgili bilgilerin sorulduğu bir sayfa karşılıyor. Tüm tutorial çerçevesinde aynı şekilde ilerlemek adına buradaki bilgileri aşağıdaki şekilde doldurabilirsiniz.

  • Name: spring-hazelcast
  • Group: com.bahadirakinspring-boot-dependencies
  • Artifact: spring-hazelcast
  • Package: com.bahadirakin.hazelcast

Bilgileri doldurup, tekrardan next dediğimizde, bizi kullanmak istediğimiz teknolojileri seçtiğimiz bir sayfa karşılıyor. Buradan Web, JPA ve h2 ile ilgili kutucukları işaretleyip next diyoruz.

Son olarak proje adını girip kurulumumuzu tamamlıyoruz. Intellij bizim için projeyi oluşturuyor. Burada maven projesi olduğunu görmeye biliyor. Bu sebepten tekrardan maven projesi olduğunu belirterek sorunu çözüyoruz.

Eğer kendimiz yapmaya kalksaydık, application-context.xml dosyasından web.xml dosyasına kadar farklı farklı bir ton dosya oluşturup tanımlamalar yapmamız gerekecekti. Fakat şu anda projeniz hazır. Tek yapmanız gereken, domain, dao ve servislerinizi yazmak. Ek olarak hiç bir servlet container’a ya da maven plugin’ine ihtiyacımız yok. Doğrudan SpringHAzelcastApplication sınıfından projemizi başlatabiliriz.

Kurulum sırasında tek yapmadığımız hazelcast ile ilgili bağımlılıkları eklemekti. Bunu daha önceki projelerde olduğu gibi manuel yapmaya devam edeceğiz. Bu sebepten ilk ve son kez xml dosyası düzenliyoruz. pom.xml dosyasını açıp içerisine aşağıdaki bağımlılığı ekliyoruz.

pom.xml

Entity, Dao ve Rest Servis

Öncelikle temel akışımızı yapalım. Bir User nesnesi için önce Entity’mizi, daha sonra SpringData kullanarak Dao katmanımızı, daha sonra SpringMVC üzerinden REST servislerimizi yazalım. Normal şartlarda REST servislerimiz ile Dao katmanımız arasında bir Servis katmanımız daha olur. Fakat projeyi basitleştirmek adına bu katmanı atlıyorum.

src/main/java altına com.bahadirakin.hazelcast.domain isminde bir paket yaratıp içerisine User.java sınıfını yaratıyoruz. Java sınıfımız aşağıdaki gibi olacak.

User.java

Entity sınıfımızı yarattığımıza göre şimdi Dao katmanımızı yazabiliriz. Bunun için src/main/java altına, com.bahadirakin.hazelcast.dao isminde bir paket yaratıyoruz ve içerisine UserRepository isminde bir interface yaratıp içerisini aşağıdaki gibi yapıyoruz.

UserRepository.java

Burada gerekli olan işlemleri SpringData bizim için halledecek. Şimdi ise hazelcast kullanmadan REST servislerimizi yazalım. Daha sonra bu REST servisi, tabiri caiz ise “cached” data üzerinden nasıl çalıştıracağımıza bakacağız. Şimdi doğrudan Dao üzerinden işlem yapacak.

Rest servisimiz için için src/main/java içerisine com.bahadirakin.hazelcast.rest isminde paket yaratıp içerisine UserRestService.java ismindeki sınıfı yaratıyoruz.

UserRestService.java

Son olarak uygulamamızı test etmek için bir import.sql dosyası oluşturabilirsiniz ya da doğrudan servis üzerinden veri basmaya çalışabilirsiniz. Eğer import.sql ile yapmak istiyorsanız src/main/resources altına import.sql dosyası oluşturun ve içeriğini aşağıdaki gibi değiştirin. Uygulama ayağa kalkarken otomatik olarak import.sql dosyasını yükleyecektir.

import.sql

Şimdi SpringHazelcastApplication sınıfını çalıştırıp uygulamanızı test edebilirsiniz. Uygulamanızı çalıştırdıktan sonra http://localhost:8080/user/bhdrkn adresine geldiğinizde size aşağıdaki çıktıyı üretecektir.

Hazelcast

Hızlıca servis yapımızı kurduk. Şimdi ise bunu “cache”‘ten nasıl çalıştırabileceğimize bakalım. Başta bahsettiğim şeyleri yerine getirmek için bir MapStore kullanacağız. MapStore içerisinde, ayarlarda belirttiğimiz map’te ilgili kaydı bulamadığında  ya da ilgili kaydı güncellemesi gerektiğinde ne yapması gerektiğini belirteceğiz. Bunun için com.bahadirakin.hazelcast klasörüne UserMapStore isminde bir java sınıfı tanımlıyoruz ve içeriğini aşağıdaki gibi yapıyoruz.

UserMapStore.java

Burada değinmek istediğim kısımlar aşağıdaki gibi;

  • Biz username bilgisini key olarak kullanacağız. Siz kendi MapStore’unuzda başka bir stateji belirleyebilirsiniz.
  • store*: Tüm store metodları bizim vereceğimiz zaman aralığında çalışacak. Yani map’imize yeni bir kayıt attığımızda ya da map’imizdeki bir kaydı güncellediğimizde çalışacak. Başta dediğimiz gibi 60 sn’de bir çalışacak şekilde ayarlayacağız.
  • load: Eğer map’te bizim gönderdiğimiz key ile ilgili, ki biz username’i key olarak kullanıyoruz, kayıt yoksa bu metod çağırılıyor.
  • loadAll: Map’imizi yaratırken, map’imizi ne şekilde doldurabileceğimizi belirtebiliyoruz. İki farklı alternatifimiz var, EAGER ve LAZY. Adlarından tahmin edebileceğiniz gibi EAGER map ayağa kalkerken tüm kayıtları çekerken, LAZY sadece KEY’leri yüklüyor. EAGER ile ayağa kaldırdığınızda loadAll metodu ile tüm data yüklenecektir.
  • loadKeys: EAGER ve LAZY metodunda ilk önce tüm keyler çekiliyor.
  • delete*: Map’ten kayıt silindiğinde ne yapılması gerektiğini belirtiyoruz. Bu örnekte map’ten silindiğinde veritabanından da silmek istiyoruz.

MapStore’umuzun nasıl çalışacağını belirlediğimize göre, şimdi Hazelcast ayarlarını yapabiliriz. Bunun için XML yazmayacağız. SpringHazelcastApplication sınıfı aynı zamanda @Configuration sınıfı. Bu sebepten buraya ekleyeceğimiz her @Bean tanımı otomatik olarak context’imizde bulunacak. Bunun için SpringHazelcastApplication sınıfını aşağıdaki gibi güncelliyoruz.

SpringHazelcastApplication.java

Burada ayarların karışık gibi gözükmesi sizi korkutmasın. Sadece iç içe fazlaca nesne tanımlanıyor. Kısaca değinecek olursak;

  • Burada Cache’imiz aynı zamanda da dağıtık olduğundan, port bilgisi belirliyoruz.
  • SSL kullanmadığımızı belirliyoruz
  • SetWriteDelaySeconds kısmında ne kadar zamanda bir veritabanı ile senkron olacağını belirliyoruz.
  • Az önce Lazy ve Eager kısmından bahsetmiştim, burada Lazy olduğunu belirliyoruz.

Son olarak UserRestService’imizi doğruca Dao ile değilde Cache’imiz ile çalışacak hale getiriyoruz. Bunu yaptıktan sonra UserRestService sınıfımızın son hali aşağıdaki gibi oluyor.

UserRestService.java

Burada neyin nasıl çalıştığını en iyi Breakpoint koyarak takip edebilirsiniz. MapStore ve Rest servislerinize koyacağınız Breakpointler sizin için yeterli olacaktır Son durumda projenizin çalıştığını, SpringHazelcastApplication sınıfnı çalıştırarak doğrulayabilirsiniz.

Son

octobiwanSpringBoot, SpringData, SpringMVC ve Hazelcast’i içeren bir uygulama yapmış olduk. Tabi Hazelcast’in doğrudan böyle kullanılması ne kadar doğru, hazelcast’i Hibernate’in second level cache’i olarak tanımlasaydık daha mı doğru olurdu gibi sorulardan çok, Hazelcast ile Spring’in nasıl entegre olacağı sorularına cevap vermeye çalıştım. Umarım yararlı olmuştur. Uygulamanın son haline aşağıdaki git adresinden erişebilirsiniz.

Hazelcast XML Konfigurasyonu

Spring konfigurasyonunu annotasyon ile değilde xml ile yapanlar için aynı hazelcast ayarlarını içeren xml dosyasını da paylaşıyorum.

 End Of Line

  1 Comment

  1. Bahadır AKIN   •     Yazar

    SpringBoot, SpringData, SpringMVC ve hazelcast’in nasıl entegre edileceği anlatılmıştır.

Yorumlama kapalıdır.