Spring Boot & MiniBank'a Giriş
Teknik detaya girmeden önce kısa bir oryantasyon: bu eğitimde ne inşa edeceğiz, nasıl çalışacağız, ortam nasıl kurulacak? Sonunda da elimizdeki MiniBank iskeletini tanıyacağız. Bu modülde kod yazmıyoruz; ortamı kuruyoruz ve haritayı çıkarıyoruz.
Mini sözlük: Aynı dili konuşalım
Eğitim boyunca sık geçecek birkaç kelimeyi en baştan netleştirelim. Bu modülde derinleşmiyoruz; sadece kelimelerin ne anlama geldiğini oturtuyoruz.
Spring Boot
Spring uygulamasını hızlı ve standart şekilde ayağa kaldırmamızı sağlayan framework'tür. Tekrar eden altyapı kararlarının çoğunu bizim yerimize verir.
MiniBank
Eğitim boyunca adım adım geliştireceğimiz örnek bankacılık uygulamasıdır. Her modül bu tek ürünün üstüne yeni bir katman ekler.
Lab Dashboard
MiniBank'in localhost:8080'de açılan kontrol panelidir. Her case'in görev listesi, doğrulama komutları ve referans kodu buradadır.
Branch / Checkpoint
Her case'in bir start ve bir complete branch'i vardır. Bir case'in complete'i, bir sonrakinin start'ıdır; böylece herkes aynı noktadan devam eder.
JDK 17
Projeyi derlemek ve çalıştırmak için gereken Java sürümüdür. MiniBank Java 17 ile yazılmıştır.
Maven Wrapper
./mvnw komutu, sistemde Maven kurulu olmasa bile projeyi doğru sürümle derleyip çalıştırır. Ayrı kurulum gerektirmez.
Embedded Server
Spring Boot uygulaması harici bir sunucuya ihtiyaç duymadan kendi içindeki web server (Tomcat) ile ayağa kalkar.
Starter
Bir özellik ailesini tek bağımlılıkla projeye ekleyen pakettir. Örneğin spring-boot-starter-web web katmanının ihtiyaçlarını birlikte getirir.
Bu eğitimde ne yapacağız?
Üç gün ve 11 modül boyunca tek bir ürün inşa edeceğiz: MiniBank. Sıfırdan başlayıp birikimli olarak production'a yakın bir olgunluğa ulaşacağız.
Bu eğitim bağımsız örneklerden oluşmaz. Her modül bir öncekinin bıraktığı yerin üstüne yeni bir yetenek ekler: önce çekirdek servis katmanı, sonra web katmanı, en sonunda güvenlik, veri ve gözlemlenebilirlik. Modül sonunda elinde ezberlenmiş parçalar değil, çalışan ve anlamlı bir banka API'si olur.
- 01 · Internal Mechanics
- 02 · IoC & Bean Model
- 03 · Spring AOP
- 04 · MVC Internals
- 05 · REST API Properly
- 06 · Exception Handling
- 07 · Config & Profiles
- 08 · Spring Security
- 09 · Data & Transactions
- 10 · External API Calls
- 11 · Observability
Her case'in complete branch'i bir sonraki case'in start branch'idir. Bu yüzden geride kalsan bile bir sonraki modüle herkesle aynı noktadan girersin.
Spring Boot neden var?
Spring Boot'un temel vaadi sade: "Sen iş mantığına odaklan; uygulamayı ayağa kaldırmak için gereken standart parçaları ben hazırlayayım."
Bir web uygulaması yazmak sadece controller yazmak değildir. HTTP isteğini karşılayacak bir sunucu, isteği doğru metoda yönlendiren bir mekanizma, JSON dönüşümü, hata yönetimi, konfigürasyon okuma ve daha fazlası gerekir. Spring Boot bu tekrar eden parçaları yaygın ve güvenli varsayılanlarla hazırlar. Bu modülde sadece bu çerçeveyi tanıyoruz; nasıl çalıştığını Modül 01'de açacağız.
Convention over Configuration
Mantıklı varsayılanlar sayesinde her şeyi tek tek ayarlamak zorunda kalmazsın; sadece farklı olmasını istediğin yeri değiştirirsin.
Embedded Server
Uygulama kendi içindeki Tomcat ile ayağa kalkar; harici sunucu kurup deploy etme adımı ortadan kalkar.
Starter Bağımlılıkları
Bir özelliğin ihtiyaç duyduğu kütüphaneleri tek tek toplamak yerine tek bir starter ile getirirsin.
Auto configuration, component scan ve bean lifecycle'ın nasıl çalıştığını burada açmıyoruz; o, Modül 01'in (Internal Mechanics) işidir. Şimdilik "Spring Boot bizim için neyi hallediyor" büyük resmini kurmak yeterli.
Nasıl çalışacağız?
Her modülde aynı akışı izleyeceğiz: önce portalda öğren, sonra dashboard'da case'i aç, eğitmenin erişime açtığı private lab repository'sini klonla, kendin yaz ve test ile doğrula.
MiniBank-Lab-NN erişime açıldığında repository'yi klonla; çalışma branch'i main'dir.Yalnız eğitmenin açtığı lab repository'leri görünür. Referans çözüm katılımcı repository'sinde bulunmaz; eğitmen case kapanışında kararları ve kodu birlikte gösterir.
Geliştirme ortamı
Tek ihtiyacın JDK 17 ve projeyi klonlamak. Maven'ı ayrı kurmana gerek yok, çünkü proje kendi wrapper'ı (./mvnw) ile gelir.
Adım 1: JDK 17'yi doğrula
Terminali aç ve aşağıdaki komutu çalıştır. Çıktının ilk satırında 17 görmen gerekiyor. 11 veya 8 görüyorsan proje derlenmez; 21 gibi daha yeni bir sürüm de çalışır ama eğitimde herkesin aynı sürümde olması sorun ayıklamayı kolaylaştırır.
$ java -version
openjdk version "17.0.11" 2024-04-16 # ilk satırda 17 olmalı
OpenJDK Runtime Environment Temurin-17..."command not found" alıyorsan JDK kurulu değil demektir; aşağıdaki indirme linklerinden Temurin 17'yi kur ve terminali kapatıp yeniden aç.
Adım 2: Açılan ilk lab repository'sini klonla
git clone https://github.com/definex-training/MiniBank-Lab-00.git
cd MiniBank-Lab-00
git branch # * main görmelisinKatılımcıların GitHub repository'lerine push yetkisi yoktur. Kodunu yerel klonunda yazarsın; eğitmen sıradaki repository'yi panelden açana kadar sonraki lab görünmez.
Adım 3: Çalıştır ve doğrula
./mvnw spring-boot:run # Windows'ta: mvnw.cmd spring-boot:run
İlk çalıştırma birkaç dakika sürebilir çünkü Maven önce bağımlılıkları indirir. Konsolda neler olacağını İlk Çalıştırma bölümünde satır satır göreceğiz. Uygulama kalktığında tarayıcıdan http://localhost:8080 adresini aç: Lab Dashboard seni karşılar. http://localhost:8080/api/status ise uygulamanın UP olduğunu söyleyen bir JSON döner. Port varsayılan olarak 8080'dir; base projede henüz özel bir application.yml yoktur, her şey Spring Boot'un varsayılanlarıyla çalışır.
# Çalışırken eksik scaffold build'i kesmez
./mvnw test -Dminibank.lab.mode=learning -Dtest=MiniBankLabCheckpointTests
# Case sonunda eksik veya yanlış davranış fail olur
./mvnw test -Dminibank.lab.mode=checkpoint -Dtest=MiniBankLabCheckpointTestsAraçlar & indirme linkleri
Eğitim için gereken ve işini kolaylaştıran araçlar. JDK 17, IntelliJ IDEA ve Git zorunlu; gerisi opsiyonel.
JDK'yı paket yöneticisiyle de kurabilirsin: brew install temurin@17 (macOS Homebrew) veya SDKMAN ile sdk install java 17-tem.
Projeyi IntelliJ'de aç
Eğitim boyunca kodu IntelliJ IDEA içinde yazacağız. Projeyi ilk kez açarken şu adımları izle; toplamda 2-3 dakika sürer.
MiniBank klasörünü seç. pom.xml'i değil, klasörün kendisini seçmek yeterli.
Her şey yolundaysa sol taraftaki proje ağacında src/main/java klasörü mavi (source root) görünür ve MiniBankApplication sınıfının yanında yeşil çalıştırma oku belirir. Bu oka tıklayarak uygulamayı IDE içinden de başlatabilirsin; terminaldeki ./mvnw spring-boot:run ile aynı işi yapar.
IDE'den çalıştırmak gündelik geliştirmede pratiktir. Terminal komutunu da öğreniyoruz çünkü test doğrulamalarını (./mvnw test) ve CI ortamlarındaki davranışı IDE olmadan da çalıştırabilmen gerekir.
pom.xml: Projenin kimlik kartı
pom.xml, Maven'a "bu proje nedir, neye ihtiyaç duyar, nasıl derlenir" sorularının cevabını veren dosyadır. MiniBank'in gerçek pom.xml'inden en önemli kısımlara bakalım.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version> <!-- Spring Boot sürümü -->
</parent>
<properties>
<java.version>17</java.version> <!-- JDK 17 şartı -->
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <!-- REST + Tomcat -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <!-- @NotBlank vb. -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <!-- /actuator/health -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <!-- JUnit + MockMvc -->
</dependency>
</dependencies>parent ne işe yarar?
spring-boot-starter-parent, yüzlerce kütüphanenin birbiriyle uyumlu sürümlerini tek yerden yönetir. Bu yüzden bağımlılıklarda tek tek <version> yazmıyoruz: sürümü parent belirler, çakışma derdi bizden kalkar.
starter ne getirir?
Tek satır starter-web eklemek; Spring MVC, JSON dönüşümü için Jackson ve embedded Tomcat'i birlikte getirir. Maven bu zinciri (transitive dependency) senin yerine çözer.
scope: test nedir?
starter-test yalnızca test derlenirken classpath'e girer; üretim jar'ına dahil olmaz. JUnit 5, AssertJ ve MockMvc bu paketle gelir.
enforcer ne yapar?
pom'daki maven-enforcer-plugin JDK 17 altı bir sürümle derlemeyi daha en başta, anlaşılır bir mesajla durdurur. Yanlış JDK ile dakikalarca hata aramazsın.
./mvnw, projenin içinde sabitlenmiş Maven sürümünü indirir ve onu kullanır. Böylece "bende çalışıyor, sende niye çalışmıyor" sorununun bir kaynağı daha kapanır: herkes aynı Maven sürümüyle derler, kimsenin makinesine ayrıca Maven kurması gerekmez.
İlk çalıştırma: konsolda ne göreceksin?
./mvnw spring-boot:run dediğinde arka arkaya dört şey olur. Konsol çıktısını okuyabilmek, ileride sorun ayıklarken en çok işine yarayacak beceridir.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
...
:: Spring Boot :: (v3.5.0)
INFO ... : Starting MiniBankApplication using Java 17
INFO ... : Tomcat initialized with port 8080 (http)
INFO ... : Root WebApplicationContext: initialization completed
INFO ... : Tomcat started on port 8080 (http) with context path '/'
INFO ... : Started MiniBankApplication in 1.8 secondsSon iki satır kritik: "Tomcat started on port 8080" web sunucusunun dinlemede olduğunu, "Started MiniBankApplication" ise Spring context'inin sorunsuz kurulduğunu söyler. Bu iki satırı görmeden tarayıcıda adres açmaya çalışma; göremiyorsan Sorun Giderme bölümüne bak.
http://localhost:8080açılıyor ve Lab Dashboard görünüyor.http://localhost:8080/api/statusşu JSON'u dönüyor:{"application":"MiniBank","status":"UP",...}http://localhost:8080/actuator/healthda{"status":"UP"}dönüyor (actuator starter'ın hediyesi).- Durdurmak için terminalde
Ctrl+C.
Base project turu
lab-00-base bilinçli olarak neredeyse boş bir iskelettir: sadece uygulamanın ayağa kalkması ve dashboard'un servis edilmesi için gereken minimum vardır. Domain (hesap, müşteri, transfer…) henüz yoktur. Onları modül modül biz ekleyeceğiz.
minibank
├── pom.xml # Spring Boot 3.5.0 · Java 17
├── mvnw / mvnw.cmd # Maven Wrapper
└── src
├── main
│ ├── java/com/definex/minibank
│ │ ├── MiniBankApplication.java # @SpringBootApplication (giriş noktası)
│ │ └── web
│ │ └── HomeController.java # GET /api/status
│ └── resources
│ └── static
│ └── index.html # Lab Dashboard
└── test/java/com/definex/minibank
├── MiniBankApplicationTests.java # context ayağa kalkıyor mu
└── MiniBankHomeControllerTests.java # status + dashboardBaşlangıçta NE VAR?
Uygulama giriş noktası (MiniBankApplication), tek bir HomeController (/api/status), statik Lab Dashboard ve iki temel test. pom.xml'de yalnızca web, validation ve actuator starter'ları.
Henüz NE YOK?
Domain paketleri yok: account, customer, transfer, security, persistence gibi paketler eğitim ilerledikçe ilgili modüllerde eklenecek.
src/main/java
Uygulamanın gerçek kodu burada yaşar. Üretim jar'ına giren her şey bu ağaçtan derlenir. Eğitim boyunca yazacağın sınıfların neredeyse tamamı buraya gidecek.
src/test/java
Testler burada yaşar; aynı paket yapısını aynalar ama üretim jar'ına girmez. Her case'in "bitti" tanımı bu ağaçtaki testlerin yeşil olmasıdır: ./mvnw test.
Giriş noktası: MiniBankApplication
Projedeki en küçük ama en önemli sınıf budur. Base projedeki gerçek hali şu:
package com.definex.minibank;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MiniBankApplication {
public static void main(String[] args) {
SpringApplication.run(MiniBankApplication.class, args);
}
}
@SpringBootApplication tek bir annotation gibi görünür ama aslında üç annotation'ın kısaltmasıdır. Şimdilik isimlerini tanıman yeterli; her birinin mekanizmasını Modül 01'de tek tek açacağız:
@SpringBootConfiguration
"Bu sınıf bir konfigürasyon kaynağıdır" der. Uygulamanın tanım merkezi burasıdır.
@EnableAutoConfiguration
"Classpath'te ne görüyorsan ona göre kurulum yap" der. starter-web varsa Tomcat ve MVC bu sayede kendiliğinden kurulur.
@ComponentScan
"Bu paketten aşağı doğru tara, bulduğun bileşenleri yönet" der. Paket kök kuralının dayandığı yer burası.
İlk controller: HomeController
/api/status cevabını üreten sınıf da base projede hazır. İki annotation'a dikkat: @RestController sınıfı "HTTP isteklerine JSON cevap veren bileşen" yapar, @GetMapping ise metodu belirli bir URL'e bağlar. Dönen record tipini Spring otomatik olarak JSON'a çevirir; bu dönüşümün perde arkasını Modül 04'te göreceğiz.
@RestController
public class HomeController {
@GetMapping("/api/status")
public MiniBankStatus status() {
return new MiniBankStatus(
"MiniBank",
"UP",
"MiniBank API calisiyor.",
List.of(
"GET / (Lab Dashboard)",
"GET /api/status",
"GET /actuator/health"));
}
public record MiniBankStatus(
String application,
String status,
String message,
List<String> links) {
}
}Paket kök kuralı
Tüm kod com.definex.minibank kök paketinin altında durur. MiniBankApplication bu kökte olduğu için, eklediğimiz her alt paket (account, customer …) otomatik olarak görülebilir konumda olur. Bunun neden böyle olduğunu Modül 01'de (component scanning) açacağız.
Base project'i ve ilk çalıştırma adımlarını dashboard üzerinden de takip edebilirsin.
Takıldıysan: en sık görülen 5 sorun
İlk kurulumda bir şeyler ters gittiyse büyük ihtimalle aşağıdakilerden biridir. Belirtiyi bul, çözümü uygula; hiçbiri tutmazsa eğitmene konsol çıktısının son 20 satırını göster.
Başka bir uygulama (ya da unutulmuş eski bir MiniBank süreci) portu tutuyor. macOS/Linux'ta lsof -i :8080 ile süreci bul, kill <PID> ile kapat. Windows'ta netstat -ano | findstr 8080 sonra Görev Yöneticisi'nden sonlandır. En pratik yol: açık kalan eski terminalde Ctrl+C.
Terminalin eski bir JDK kullanıyor. java -version ile kontrol et. Birden çok JDK kuruluysa JAVA_HOME'u 17'ye işaret ettir; macOS'ta export JAVA_HOME=$(/usr/libexec/java_home -v 17) yeterli. IntelliJ içinde ayrıca Project Structure → SDK = 17 olmalı.
Wrapper dosyası çalıştırma izni kaybetmiş. chmod +x mvnw ile izni geri ver. Windows'ta bu sorun olmaz; orada mvnw.cmd kullanılır.
Ağ ya da proxy sorunu. Kurumsal ağdaysan VPN/proxy ayarlarını kontrol et; gerekiyorsa ~/.m2/settings.xml dosyasına proxy tanımı ekle. Yarıda kesilen indirme bozuk dosya bırakabilir: rm -rf ~/.m2/repository/org/springframework deyip tekrar dene.
Maven import tamamlanmamış ya da cache karışmış. Sağdaki Maven panelinden "Reload All Maven Projects" butonuna bas. Düzelmezse File → Invalidate Caches → Invalidate and Restart.
Bu modülden akılda kalması gerekenler
11 modül, 3 gün; her case bir öncekinin üstüne ekler. Sonunda çalışan bir MiniBank API'si.
Portalda öğren → dashboard'da case aç → start branch → kendin yaz → test ile doğrula.
lab-NN-complete ile herkes aynı noktadan devam edebilir; kopyala-yapıştır değil, branch klonlanır.
JDK 17 + ./mvnw spring-boot:run. Base proje localhost:8080'de ayağa kalkar.
Sadece MiniBankApplication + HomeController + dashboard var; domain paketlerini biz ekleyeceğiz.
"Tomcat started on port 8080" + "Started MiniBankApplication" çifti sağlıklı kalkışın imzasıdır; bu satırlar yoksa önce Sorun Giderme'ye bak.
Ortamın çalışıyor ve haritayı gördüysen, ilk teknik modüle geçebilirsin.