Java 9 Yenilikleri-2-Modüler Java

0 4,088

Bu makalede JDK 9 ile gelen modüler olma yaklaşımından bahsetmeye çalışacağız. Yol haritamız aşağıdaki gibi olacaktır.

  • Project Jigsaw
  • Modülerlik
  • Modül
  • JDK 9 Öncesi
  • JDK 9 – Java Platform Module System

Project Jigsaw

20 yılı aşkın süredir var olan Java’ya, modüler yapıyı eklemek pek de kolay olmadı. Ağustos 2008’de başlayan yolculuk, Ağustos 2014 de koda dönüşmeye başladı. Temmuz 2017 itibari ile de proje tamama ermiş oldu.

Project Jigsaw’ın amaçları;

* Geliştiricilerin, kütüphaneleri veya büyük çaplı uygulamaları geliştirmesini ve bakımını kolaylaştırmak.
* Java SE platform uygulamalarının ve JDK’nın güvenliğini ve bakım yapılabilirliğini geliştirmek
* Java uygulama performanslarını geliştirmek
* Cloud ortamlarda ve mobile vb küçük cihazlarda ölçeklenebilir Java platformu oluşturmak

Bu amaçlara ulaşabilmek için, 7 adet geliştirme spesifikasyonu oluşturuldu ve projenin adına jigsaw denildi.

* Modular JDK
* Modular Source Code
* Modular Run-Time Images
* Encapsulate Most Internal APIs
* Module System
* jlink : The Java Linker
* Java Platform Module System

Modülerlik

Modülerlik kavramı hayatın bir çok alanında karşımıza çıkar. Modülerlik birbirinden bağımsız ama bir biri ile uyumlu parçalardan(modül) ihtiyaca göre bir bütün elde edebilme yaklaşımıdır.

Yazılım açısından baktığımızda ise bir yazılım dizayn tipidir. Örneğin Spring modüler yaklaşım üzerine inşa edilmiş bir çatıdır. Istediğimiz modülü ekleyip, özelliklerini kullanırız. Modül ekleme ve çıkarma işlemleri uygulamamızın ana yapısını etkilemez. Modüller bir araya gelip daha işlevsel bir yapı oluşturur. Bu sayede, kullanmayacağımız modülleri uygulamamız içerisine almamış oluruz.

Modül

Modulü ise şöyle tanımlayabiliriz;

* kendi kendine yetebilen
* farklı modüller ile çalışabilen
* kendisini ve diğer modüller ile etkileşimini tanımlayan metadatası olan
* kod ve çeşitli kaynaklar içeren yazılım birimleridir.

Bu tanım üzerinden yola çıkarsak bir modülün uyması gereken bazı ilkeler vardır;

*Bir modül, diğer modüllerin erişimini kontrol edebilmelidir. Diğer bir değiş ile, dışarıya açacağı kodu kendisi belirlemelidir.
*Bir modül iyi tanımlanmış arayüzlere sahip olmalıdır. Diğer modüller ile bunlar üzerinden etkileşime girecektir.
*Bir modül kendi bağımlılıklarını, kendi tanımlayabilmelidir.

JDK 9 Öncesi

Her yazılımcının bir projeye başlarken ki hedefi, katmanları birbirinden kesin hatlar ile ayrılmış, katmanlar arası iletişim arayüzleri net bir şekilde belirlenmiş ve bu arayüzler dışında katmanların birbirine erişiminin olmadığı bir yapı kurabilmektir. JDK 9 öncesi bunu tam anlamı ile gerçekleştiremiyorduk.

Modül ilkeleri üzerinden JDK 9 öncesini inceleyelim;

Encapsulation paket ve access modifier’ların bir arada kullanılması ile oluşturulmaya çalışılıyordu. Bu çaba kısıtlı bir encapsulation sunuyordu. Paket ve access modifier kombinasyonlarını arayüz ile desteleyebiliyorduk fakat bu yapıyı oluşturmanın zorlukları vardı. Ayrıca public arayüzlerin bir yere yazılmaması nedeni ile takibi zor oluyordu.

Bağımlılıkları ise proje bazlı olarak maven, gradle vb araçlar ile yapıyorduk. Kütüphaneler arası bağımlılıklar bu araçlar ile düzenleniyordu. Bağımlılıkları kendimizin tanımlaması, uygulama çalışırken classpathe set etmemiz gerekiyordu. Ya da maven vb araçlar ile classpath’i düzenliyorduk. Bağımlılıklarda yapılacak bir hata runtime’da ilgili sınıfa ihtiyaç duyulduğunda exception olarak karşımıza çıkıyordu. Aynı sınıfın farklı versiyonlarının yüklenmesi ile veya ClassNotFoundException ile java ile uğraşan herkes bir kaç defa karşılaşmıştır.

Java Platform Module System

Java Platform Module System spesifikasyonu ile javaya modul sistemi adapte edildi.

Bir java modulü istenilen paketi dışarı açabilir, veya encapsule edebilir ayrıca diğer modullere bağımlılıklarını kesin bir şekilde belirtir. Gördüğümüz gibi, bir modul olabilmenin şartları artık tam olarak karşılanabilmektedir. Bir örnek üzerinden modul yapısına giriş yapalım.

Çok basit bir mesaj kuyruğu uygulaması yapalım. Örneğimizi Eclipse Oxygen 4.7.1a idesi ile JDK-9.0.1 ile yapacağız.

İki ayrı projemiz olacak. QueueApp isimli proje ana projemiz olacak. RepositoryUtil isimli projeyide, ana projemizin module path’ine ekleyeceğiz (Artık classpath yok). QuqueApp isimli uygulamamız, mesajları farklı kaynaklardan alıp, aldığı mesajda belirtildiği şekilde hedef sistemlere gönderecek. Biz sadece hedef sistemler kısmını yapacağız.

QueueApp, RepositoryUtil modülüne sadece Sender isimli sınıf üzerinden erişebilecek. Diğer sınıflarını kullanamayacak.

İlk olarak modül projemizden başlayalım.

1* RepositoryUtil isimli bir proje oluşturuyoruz.
2* 4 adet paket oluşturuyoruz.

  • io.bilisim.integration.entity
  • io.bilisim.processor
  • io.bilisim.sender
  • io.bilisim.template

io.bilisim.integration.entity paketimizden başlayalım. Bu paket içerisinde

TargetType enum tipimiz ve SenderEntity isimli bir sınıfımız olacak.

io.bilisim.template paketimiz ile devam edelim. IProcessor isimli bir interface yapacağız. Processor’lerimiz bu interface’i implemente edecek.

io.bilisim.processor paketimiz ile devam edelim. Bu paket içerisinde hedef sistemlere mesajımızı iletecek sınıflarımız olacak.

io.bilisim.sender paketine geçmeden önce, TargetType enum içerisinde bir düzenleme yapacağız. Her tipin processor sınıfının bir örneğini döndüren metotları ekleyeceğiz.

Son olarak io.bilisim.sender paketimizin içerisiğini oluşturalım.

Şuana kadar standart bir java projesi yaptık. Şimdi projemizin üzerine sağ tıklayıp module-info.java dosyamızı ekleyeceğiz.

configure -> create module-info.java ile bu işi yapıyoruz. module isimlendirmesi küçük harf ile yapılmalı.

module-info.java dosyası, modülün metadatasını tutan dosyadır. Şimdi biz bu dosya içerisine, repositoryUtil modülümüzün export edeceği paket bilgilerini vereceğiz.

Bu tanım ile, io.bilisim.sender ve io.bilisim.integration.entity paketlerini dışarıya açmış olduk. Ayrıca istersek modül ismi de vererek sadece o modülün erişmesini de sağlayabiliriz.

exports io.bilisim.sender to queueApp;
exports io.bilisim.integration.entity to queueApp;

QueueApp isimli bir proje oluşturup içerisine io.bilisim.core isimli bir paket ve QueueProcessor isimli bir sınıf ekleyelim.

Bu projemizin içerisine de module-info.java dosyamızı ekleyip içerisini aşağıdaki gibi dolduralım.

requires ile, bu modülümüzün hangi modüle ihtiyaç duyduğunu gösterdik.

Buraya kadar olanları yaptıysanız,

Sender cannot be resolved to a type” ve  “repositoryUtil cannot be resolved to a module” hatalarını görmüş olmalısınız. Çünkü QueueApp projemizin module pathini düzenlemedik. Bunun için,

Build Path -> Configure Build Path ile aşağıdaki ekranı açacağız. Project tabı altında, Modulepath’e RepositoryUtil projemizi ekliyoruz. Artık hatalardan kurtulduk.

 

Buraya kadar yaptıklarımıza bir bakar isek,

Harici olarak bağımlılıkları tanımladık. Güçlü bir encapsulation meydana getirdik ve iletişim için bir arayüz oluşturduk. QueueApp üzerinden, RepositoryUtil modülümüzde dışarıya açılmamış sınıflara örneğin ConsoleClient’a erişmek istersek;

The type io.bilisim.processor.ConsoleClient is not accessible” hatasını alırız.

QueueProcessor sınıfını çalıştırdığımızda,

Console: Merhaba Java 9 çıktısını almış olmalıyız.

Java ile modülerlik konusuna başlangıç yapmış olduk. Bir sonraki makalemizde kaldığımız yerden devam edeceğiz inşallah. Umarım faydalı olmuştur.

Gayret bizden, tevfik Allah’tan.

Email adresiniz yayınlanmayacaktır.