1. Genel Bakış
Bu codelab'de Spring Native projesi hakkında bilgi edinecek, bu projeyi kullanan bir uygulama oluşturacak ve uygulamayı Google Cloud'da dağıtacağız.
Bu araçla ilgili bileşenleri, projenin son geçmişini, bazı kullanım alanlarını ve elbette projelerinizde kullanmak için gereken adımları ele alacağız.
Spring Native projesi şu anda deneysel aşamada olduğundan başlamak için belirli bir yapılandırma gerektirir. Ancak SpringOne 2021'de duyurulduğu gibi Spring Native, birinci sınıf destekle Spring Framework 6.0 ve Spring Boot 3.0'a entegre edilecek. Bu nedenle, yayınlanmasından birkaç ay önce projeye daha yakından bakmak için mükemmel bir zaman.
Tam zamanında derleme, uzun süren işlemler gibi durumlar için çok iyi optimize edilmiş olsa da önceden derlenmiş uygulamaların daha iyi performans gösterdiği belirli kullanım alanları vardır. Bu kullanım alanlarını codelab sırasında ele alacağız.
Bu demoda aşağıdaki işlemleri yapmayı öğreneceksiniz:
- Cloud Shell'i kullanma
- Cloud Run API'yi etkinleştirin
- Spring Yerel Uygulaması oluşturma ve dağıtma
- Bu tür bir uygulamayı Cloud Run'a dağıtma
Gerekenler
- Etkin bir GCP faturalandırma hesabına sahip bir Google Cloud Platform projesi
- gcloud CLI'nin yüklü olması veya Cloud Shell'e erişim
- Temel Java + XML becerileri
- Yaygın Linux komutları hakkında çalışma bilgisi
Anket
Bu eğitimi nasıl kullanacaksınız?
Java ile ilgili deneyiminizi nasıl değerlendirirsiniz?
Google Cloud hizmetlerini kullanma deneyiminizi nasıl değerlendirirsiniz?
2. Arka plan
Spring Native projesi, geliştiricilere yerel uygulama performansı sunmak için çeşitli teknolojilerden yararlanır.
Spring Native'i tam olarak anlamak için bu bileşen teknolojilerinden birkaçını, bize neler sağladıklarını ve burada nasıl birlikte çalıştıklarını anlamak faydalı olacaktır.
AOT derleme
Geliştiriciler, derleme sırasında javac'ı normal şekilde çalıştırdığında .java kaynak kodumuz, bayt koduyla yazılmış .class dosyaları halinde derlenir. Bu bayt kodu yalnızca Java sanal makinesi tarafından anlaşılmak üzere tasarlanmıştır. Bu nedenle, kodumuzu çalıştırmak için JVM'nin bu kodu diğer makinelerde yorumlaması gerekir.
Bu süreç, Java'ya kendine özgü taşınabilirlik özelliğini kazandırır. Bu sayede "bir kez yazıp her yerde çalıştırabiliriz". Ancak bu süreç, yerel kod çalıştırmaya kıyasla maliyetlidir.
Neyse ki JVM'nin çoğu uygulaması, bu yorumlama maliyetini azaltmak için tam zamanında derlemeyi kullanır. Bu, bir işlevin çağrılma sayısını sayarak gerçekleştirilir. İşlev, bir eşiği geçecek kadar sık çağrılırsa ( varsayılan olarak 10.000) daha fazla maliyetli yorumlamayı önlemek için çalışma zamanında yerel koda derlenir.
Önceden derleme ise tüm ulaşılabilir kodu derleme süresinde yerel bir yürütülebilir dosyaya derleyerek tam tersi bir yaklaşım benimser. Bu, çalışma zamanında bellek verimliliği ve diğer performans kazanımları için taşınabilirlikten ödün verir.

Bu elbette bir ödünleşmedir ve her zaman almaya değmez. Ancak AOT derlemesi, aşağıdakiler gibi belirli kullanım alanlarında öne çıkabilir:
- Başlangıç süresinin önemli olduğu kısa ömürlü uygulamalar
- JIT'nin çok maliyetli olabileceği, bellek kısıtlamalarının yüksek olduğu ortamlar
İlginç bir bilgi olarak, AOT derlemesi JDK 9'da deneysel bir özellik olarak kullanıma sunulmuştu. Ancak bu uygulamanın bakımı maliyetliydi ve hiç popüler olmamıştı. Bu nedenle, geliştiricilerin GraalVM'yi kullanması tercih edilerek Java 17'de sessizce kaldırıldı.
GraalVM
GraalVM, son derece hızlı başlatma süreleri, AOT yerel görüntü derlemesi ve geliştiricilerin birden fazla dili tek bir uygulamada karıştırmasına olanak tanıyan çok dilli özellikler sunan, yüksek düzeyde optimize edilmiş bir açık kaynak JDK dağıtımıdır.
GraalVM aktif olarak geliştirilmekte, sürekli olarak yeni özellikler kazanmakta ve mevcut özellikleri iyileştirmektedir. Bu nedenle, geliştiricilerin gelişmeleri takip etmesini öneririm.
Son ara hedeflerden bazıları şunlardır:
- Yeni ve kullanıcı dostu bir yerel resim derleme çıkışı ( 2021-01-18)
- Java 17 desteği ( 2022-01-18)
- Çok dilli derleme sürelerini iyileştirmek için çok katmanlı derlemeyi varsayılan olarak etkinleştirme ( 2021-04-20)
Spring Native
Basitçe ifade etmek gerekirse Spring Native, Spring uygulamalarını yerel olarak çalıştırılabilir dosyalara dönüştürmek için GraalVM'nin native-image derleyicisinin kullanılmasını sağlar.
Bu süreçte, uygulamanızdaki giriş noktasından erişilebilen tüm yöntemleri bulmak için derleme sırasında uygulamanızın statik analizi yapılır.
Bu, uygulamanızın "kapalı dünya" konseptini oluşturur. Bu konseptte tüm kodun derleme süresinde bilindiği varsayılır ve çalışma zamanında yeni kod yüklenmesine izin verilmez.
Yerel görüntü üretmenin, normal bir uygulamayı derlemekten daha uzun süren ve Java'nın belirli yönlerinde sınırlamalar getiren, belleği yoğun olarak kullanan bir işlem olduğunu unutmamak önemlidir.
Bazı durumlarda, bir uygulamanın Spring Native ile çalışması için kod değişikliği yapılması gerekmez. Ancak bazı durumlarda, düzgün çalışması için belirli bir yerel yapılandırma gerekir. Bu gibi durumlarda Spring Native, bu süreci basitleştirmek için genellikle Native Hints (Yerel İpuçları) sağlar.
3. Kurulum/Ön Hazırlık
Spring Native'i uygulamaya başlamadan önce, uygulamamızı oluşturup dağıtarak daha sonra yerel sürümle karşılaştırabileceğimiz bir performans temel çizgisi oluşturmamız gerekir.
1. Proje oluşturma
İlk olarak uygulamamızı start.spring.io adresinden alarak başlayacağız:
curl https://start.spring.io/starter.zip -d dependencies=web \
-d javaVersion=11 \
-d bootVersion=2.6.4 -o io-native-starter.zip
Bu başlangıç uygulaması, yazıldığı sırada spring-native projesinin desteklediği en son sürüm olan Spring Boot 2.6.4'ü kullanır.
GraalVM 21.0.3 sürümünden itibaren bu örnek için Java 17'yi de kullanabileceğinizi unutmayın. Bu eğitimde, yapılandırmayı en aza indirmek için Java 11'i kullanmaya devam edeceğiz.
Komut satırında ZIP dosyamız olduğunda projemiz için bir alt dizin oluşturabilir ve klasörü burada açabiliriz:
mkdir spring-native cd spring-native unzip ../io-native-starter.zip
2. Kod değişiklikleri
Proje açıldıktan sonra hızlıca bir yaşam işareti ekleyip Spring Native'i uyguladığımızda performansını göstereceğiz.
DemoApplication.java dosyasını aşağıdaki gibi düzenleyin:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.time.Instant;
@RestController
@SpringBootApplication
public class DemoApplication {
private static Instant startTime;
private static Instant readyTime;
public static void main(String[] args) {
startTime = Instant.now();
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/")
public String index() {
return "Time between start and ApplicationReadyEvent: "
+ Duration.between(startTime, readyTime).toMillis()
+ "ms";
}
@EventListener(ApplicationReadyEvent.class)
public void ready() {
readyTime = Instant.now();
}
}
Bu noktada temel uygulamamız kullanıma hazır. Bu nedenle, yerel uygulamaya dönüştürmeden önce başlangıç süresi hakkında fikir edinmek için bir görüntü oluşturup yerel olarak çalıştırabilirsiniz.
İmajımızı oluşturmak için:
mvn spring-boot:build-image
Temel resmin boyutu hakkında fikir edinmek için docker images demo simgesini de kullanabilirsiniz: 
Uygulamamızı çalıştırmak için:
docker run --rm -p 8080:8080 demo:0.0.1-SNAPSHOT
3. Temel uygulamayı dağıtma
Uygulamamızı oluşturduktan sonra dağıtıp süreleri not edeceğiz. Bu süreleri daha sonra yerel uygulamamızın başlangıç süreleriyle karşılaştıracağız.
Geliştirdiğiniz uygulamanın türüne bağlı olarak içeriklerinizi barındırmak için çeşitli seçenekler vardır.
Ancak örneğimiz çok basit ve anlaşılır bir web uygulaması olduğundan işleri basit tutabilir ve Cloud Run'a güvenebiliriz.
Kendi makinenizde bu adımları uyguluyorsanız gcloud CLI aracının yüklü ve güncel olduğundan emin olun.
Cloud Shell'deyseniz tüm bunlar halledilir ve kaynak dizinde aşağıdaki komutu çalıştırmanız yeterlidir:
gcloud run deploy
4. Uygulama Yapılandırması
1. Maven depolarımızı yapılandırma
Bu proje hâlâ deneysel aşamada olduğundan, uygulamamızı Maven'in merkezi deposunda bulunmayan deneysel yapıları bulabilecek şekilde yapılandırmamız gerekiyor.
Bunun için aşağıdaki öğeleri pom.xml dosyamıza eklememiz gerekir. Bu işlemi istediğiniz düzenleyicide yapabilirsiniz.
Aşağıdaki depoları ve pluginRepositories bölümlerini pom'umuza ekleyin:
<repositories>
<repository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</pluginRepository>
</pluginRepositories>
2. Bağımlılıklarımızı ekleme
Ardından, Spring uygulamasını yerel görüntü olarak çalıştırmak için gereken spring-native bağımlılığını ekleyin. Not: Gradle kullanıyorsanız bu adım gerekli değildir.
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.11.2</version>
</dependency>
</dependencies>
3. Eklentilerimizi ekleme/etkinleştirme
Şimdi yerel resim uyumluluğunu ve kapladığı alanı iyileştirmek için AOT eklentisini ekleyin ( Daha fazla bilgi):
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.11.2</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
Şimdi, spring-boot-maven-plugin'i yerel görüntü desteğini etkinleştirecek ve yerel görüntümüzü oluşturmak için paketo oluşturucuyu kullanacak şekilde güncelleyeceğiz:
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
</plugins>
küçük derleyici görüntüsü, çeşitli seçeneklerden yalnızca biridir. Çok az sayıda ek kitaplık ve yardımcı program içerdiğinden saldırı yüzeyimizi en aza indirmemize yardımcı olur. Bu nedenle, kullanım alanımız için iyi bir seçimdir.
Örneğin, bazı yaygın C kitaplıklarına erişmesi gereken bir uygulama geliştiriyorsanız veya uygulamanızın gereksinimlerinden henüz emin değilseniz full-builder daha uygun olabilir.
5. Yerel uygulama oluşturma ve çalıştırma
Tüm bunlar tamamlandığında görüntümüzü oluşturup yerel, derlenmiş uygulamamızı çalıştırabiliriz.
Derlemeyi çalıştırmadan önce göz önünde bulundurmanız gereken birkaç nokta:
- Bu işlem normal bir derlemeden (birkaç dakika) daha uzun sürer

- Bu derleme işlemi çok fazla bellek (birkaç gigabayt) kullanabilir.

- Bu derleme işlemi için Docker daemon'a erişilebilmesi gerekir.
- Bu örnekte süreci manuel olarak ele alıyor olsak da derleme aşamalarınızı yerel bir derleme profilini otomatik olarak tetikleyecek şekilde de yapılandırabilirsiniz.
İmajımızı oluşturmak için:
mvn spring-boot:build-image
Bu işlem tamamlandığında doğal uygulamayı kullanmaya başlayabiliriz.
Uygulamamızı çalıştırmak için:
docker run --rm -p 8080:8080 demo:0.0.1-SNAPSHOT
Bu noktada, yerel uygulama denkleminin her iki tarafını da görebiliriz.
Derleme sırasında biraz zaman ve ek bellek kullanımından vazgeçtik ancak karşılığında çok daha hızlı başlatılabilen ve önemli ölçüde daha az bellek tüketen (iş yüküne bağlı olarak) bir uygulama elde ettik.
Yerel resmin boyutunu orijinaliyle karşılaştırmak için docker images demo komutunu çalıştırdığımızda boyutun önemli ölçüde küçüldüğünü görebiliriz:

Daha karmaşık kullanım alanlarında, AOT derleyicisine uygulamanızın çalışma zamanında ne yapacağını bildirmek için ek değişiklikler yapılması gerektiğini de belirtmek isteriz. Bu nedenle, belirli tahmin edilebilir iş yükleri (ör. toplu işler) bu iş için çok uygun olabilirken diğerleri daha fazla çaba gerektirebilir.
6. Yerel uygulamamızı dağıtma
Uygulamamızı Cloud Run'a dağıtmak için yerel görüntümüzü Artifact Registry gibi bir paket yöneticisine aktarmamız gerekir.
1. Docker depomuzu hazırlama
Bu süreci bir depo oluşturarak başlatabiliriz:
gcloud artifacts repositories create native-image-docker-repo --repository-format=docker \
--location=us-central1 --description="Repository for our native images"
Ardından, yeni kayıt defterimize aktarmak için kimliğimizin doğrulandığından emin olmamız gerekir.
gcloud CLI bu süreci oldukça basitleştirebilir:
gcloud auth configure-docker us-central1-docker.pkg.dev
2. Görüntümüzü Artifact Registry'ye gönderme
Ardından, resmimizi etiketleyeceğiz:
export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
docker tag demo:0.0.1-SNAPSHOT \
us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2
Ardından, docker push kullanarak Artifact Registry'ye gönderebiliriz:
docker push us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2
3. Cloud Run'a dağıtma
Artık Artifact Registry'de depoladığımız görüntüyü Cloud Run'a dağıtmaya hazırız:
gcloud run deploy --image us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2
Uygulamamızı yerel görüntü olarak oluşturup dağıttığımız için, uygulamamızın çalışırken altyapı maliyetlerimizden mükemmel şekilde yararlandığından emin olabiliriz.
Temel uygulamamızın başlangıç sürelerini bu yeni yerel uygulamayla kendiniz karşılaştırabilirsiniz.

7. Özet/Temizleme
Google Cloud'da Spring Native yerel uygulaması derleyip dağıttığınız için tebrik ederiz.
Bu eğitimin, Spring Native projesi hakkında daha fazla bilgi edinmenizi ve gelecekte ihtiyaçlarınızı karşılayabileceğini göz önünde bulundurmanızı sağlayacağını umuyoruz.
İsteğe bağlı: Hizmeti temizleme ve/veya devre dışı bırakma
Bu codelab için bir Google Cloud projesi oluşturduysanız veya mevcut bir projeyi yeniden kullanıyorsanız kullandığımız kaynaklardan gereksiz ücret alınmaması için dikkatli olun.
Oluşturduğumuz Cloud Run hizmetlerini silebilir veya devre dışı bırakabilir, barındırdığımız resmi silebilir ya da projenin tamamını kapatabilirsiniz.
8. Ek kaynaklar
Spring Native projesi şu anda yeni ve deneysel bir proje olsa da ilk kullanıcıların sorunları gidermesine ve projeye dahil olmasına yardımcı olacak çok sayıda iyi kaynak bulunmaktadır:
Ek kaynaklar
Bu eğitimle ilgili olabilecek online kaynakları aşağıda bulabilirsiniz:
- Doğal ipuçları hakkında daha fazla bilgi edinin.
- GraalVM hakkında daha fazla bilgi
- Nasıl katılabilirsiniz?
- Yerel görüntüler oluşturulurken yetersiz bellek hatası
- Uygulama başlatılamadı hatası
Lisans
Bu çalışma, Creative Commons Attribution 2.0 Genel Amaçlı Lisans ile lisans altına alınmıştır.