“Spring ve Java Hantal Mı - GraalVM ve Quarkus’a Giriş” yazımızda Java’nın tüm platformlarda çalışabilmesi için göz yumduğu şeylerden ve buna bir çözüm olarak ortaya atılan GraalVM’den ve nasıl çalıştığından bahsetmiştik. GraalVM’in Spring dünyası ile birlikte çalışabilmesinin güç olduğuna değinmiş ve Quarkus ile neler yapılabileceğini incelemiştik.
Aradan geçen yaklaşık 1,5 senelik süre zarfında Spring cephesinde bu konu hakkında gelişmeler oldu. Bugünkü yazımızın konusunu oluşturan bu gelişmeleri, birlikte çalışmasının neden güç olduğunu ve buna çözüm olarak nelerin yapıldığını birlikte inceleyelim.
1. Spring Native Beta Release
Spring.io blog’unda yayınlanan yazıyla önceleri Spring GraalVM Native isminde duyduğumuz yaklaşık 1,5 senedir devam eden projeyi Spring Native ismiyle Beta Release olarak 11 Mart 2021 tarihinde duyurdu. Duyuruda en başından beri Java Sanal Makinesi’ne(JVM) verilen desteğin artık native image derlemeye olanak sağlayan GraalVM için Java ve Kotlin dilleri ile verileceği haberi yer alıyor.
Bu haber şu anlama geliyor, Spring projenize dair hazırladığınız native image ile artık JVM olmadan da çalışabilir, 100ms gibi bir sürenin altında uygulamanız ayağa kalkabilir ve daha düşük memory tüketimi ile daha yüksek performansı elde edebilirsiniz! Bütün bunların nasıl gerçekleştiği bilgisini tazelemek için önceki yazıya göz atabilirsiniz.
Peki neydi bugüne kadar bunların kullanılmasının önündeki engel ve bütün bu özellikleri kullanabilmek için neler yapılması gerekiyor?
2. Dynamic Proxying
Spring AOP (aspect oriented programming), Code Generation Library (cglib) isminde kütüphane yardımıyla projelerin compile aşamasından sonra dahi classların yaratılabilmesi ve manipule edilebilmesini sağlamaktaydı. Bu işleme Dynamic Proxying ismi verilmektedir. JDK’nın içerisinde de dinamik proxyler mevcuttur, tercihe göre bunlar da kullanılabilmektedi. Özetle çalışmakta olan programınız runtimeda yeni sınıfları belleğe yükleyebilir yetenekte oluyordu. Bu da Spring’in modüler ve dinamik yapısının altında yatan gizli baş kahramandı. Hibernate, Mockito gibi popüler bir çok framework de benzer yöntemleri kullanmaktadır.
Dynamic proxying’i daha iyi anlamak için bir örnek üzerinde inceleyelim.
Örneğin yukarıdaki gibi bir sınıfın proxying yapılmadan, en düz hali ile çağırımı aşağıdaki gibi olacaktır.
Bunun yerine tüm kontrolün bir dynamic proxy aracılığıyla Spring’e devredildiği senaryo için aşağıdaki örnek incelenebilir.
Farkettiyseniz SimplePojo sınıfındaki metodumuzda değişiklikler gerçekleşti. Ancak bizim yazdığımız kodlarda bu şekilde bir implementasyon yapmıyoruz, proxy sınıflarından haberdar olmadan geliştirimlerimizi yapıyoruz. İşte bu noktada Spring AOP devreye girerek az önce bahsettiğimiz dinamik sınıf değişikliklerini gerçekleştiriyor ve belleğe bu şekilde yüklenmesi gibi fonksiyonları yerine getiriyor.
3. Projenin Yapısı
https://start.spring.io/ sitesinden inceleme amacıyla Spring Native Beta projesi yaratalım. Dependencies’i tıkladığımızda aşağıdaki gibi en başta geldiğini görebiliriz.
Önceki yazıda Just in Time (JIT) derleyici ile Ahead of Time (AOT) derleyicilerin farklarından bahsetmiştik. JIT derleyicilerde dynamic proxying yapmak mümkün iken AOT derleyiciler çalışacağı platforma bağımlı kod ürettiklerinden dolayı runtime’da sürpriz(lazy loading) sevmezler. Her şeyin build zamanında netleştirilmesi ve native image’ın buna göre oluşturulması gerekmektedir. Spring Native projesinin ilk majör farkı burada başlamaktadır.
Bu durumda Spring Bean’leri arası bindinglerinin tamamlanabilmesi için bir çok adım build zamanına kaydırılmış oldu. Bu dönüşümlerin yapılabilmesi için de Maven, Gradle gibi popüler inşa araçlarında da düzenlemeler, yeni pluginlerin oluşturulması gerekliydi. Bu değişiklikleri incelemek için oluşturduğumuz projenin pom.xml dosyasını inceleyelim.
Burada dikkat çeken 3 nokta bulunuyor. İlki Spring Boot Maven Plugin’deki image builder eki. Bu configuration sayesinde GraalVM tarafından çalıştırılacak native image çıktısı oluşturulabilecek. Bu plugin’in ekstra yapılandırmaları ve kullanımı için burayı inceleyebilirsiniz.
İkinci nokta, Ahead of Time(AOT) derlemesi için yeni bir Maven Plugin’i. Bu plugin build anında Spring stereotype annotation’larını ve aslına bakılırsa tüm bean yapılandırmalarını GraalVM’in manuel reflection yapılandırmasının içerisine eklemeyi sağlayan plugin olarak düşünebiliriz. Bu plugin’in tetiklenmesi için kullanabileceğiniz maven goal’ü aşağıda da görebileceğiniz gibi
mvn spring-aot:generate dir. Diğer konfigürasyonları için burayı inceleyebilirsiniz.
Pom.xml dosyasındaki son dikkat edilmesi gereken nokta ise versiyonlar. Şu anda Spring Native projesinin son versiyonu 0.9.1 versiyonu, Spring Boot 2.4.4’ü destekliyor. Java 8 ve 11 versiyonları ve GraalVM’in 21.0.0 versiyonu destekli. GraalVM’in Spring desteği verdiği versiyonlar bu adresten Spring tag’ine sahip versiyonlar üzerinden takip edilebilir.
4. Sonuç
Sonraki yazımızda bir Spring Native projesinin nasıl ayağa kaldırılabileceğini, IDE yapılandırmalarını, derlemeyi, Native Hint’lerini, proje performans karşılaştırmalarını ve son olarak hangi Spring Starter’ları ve çevresel Cloud Starter’ları ile birlikte kullanılabileceğini inceleyeceğiz.