Build Araçları: Maven ve Gradle
Java'da bir proje yazıp "çalıştır" tuşuna basıyorsun ve her şey sihirli bir şekilde derlenip çalışıyor. Peki arka planda ne oluyor? Kaynak dosyaları derleniyor, bağımlılıklar (dependency) indiriliyor, testler koşuluyor, JAR dosyası paketleniyor... Bu adımların hepsini elle yapmak mümkün ama gerçek dünyada kimse javac ile dosya dosya derlemiyor.
İşte build araçları tam burada devreye giriyor. Bu derste Java ekosisteminin iki büyük oyuncusunu — Maven ve Gradle — sıfırdan öğreneceğiz.
1. Build Aracı Neden Lazım?
Küçük bir Java dosyası için javac Main.java && java Main yeterli. Ama gerçek bir projede şunlar var:
50-100+ kaynak dosyası
10-30 dış kütüphane (JSON parser, HTTP client, test framework...)
Her kütüphanenin kendi bağımlılıkları (transitive dependency)
Derleme → test → paketleme → dağıtım adımları
Farklı ortamlar (dev, test, production)
Bunların hepsini elle yönetmeye çalışmak, bir inşaat projesini telefon defterine not alarak yürütmeye benzer. Bir noktadan sonra kaos kaçınılmaz.
🎯 Analoji — Yemek Tarifi ve Şef:
>
Build aracını bir şef gibi düşün. Sen tarifi (kaynak kodu) yazarsın, malzeme listesini (dependency) verirsin. Şef malzemeleri toplar, doğru sırayla hazırlar, pişirir ve tabağa koyar. Sen sadece "yap" dersin, gerisini o halleder. Maven "kurallara sıkı sıkıya bağlı, Fransız mutfağı şefi" gibiyken, Gradle "esnek, yaratıcı, modern füzyon şefi" gibidir.
2. Maven — Java'nın Klasik Build Aracı
Maven, Apache tarafından geliştirilmiş ve 2004'ten beri Java ekosisteminin bel kemiği olan build aracıdır. "Convention over Configuration" (konfigürasyon yerine kural) felsefesiyle çalışır — yani belirli kurallara uyarsan neredeyse hiç ayar yapmana gerek kalmaz.
Maven Proje Yapısı
Maven projeleri standart bir dizin yapısına sahiptir. Bu yapıyı ezberlemene gerek yok — Maven her projeyi böyle bekler:
my-project/
├── pom.xml ← Proje tanım dosyası (kalp)
├── src/
│ ├── main/
│ │ ├── java/ ← Uygulama kaynak kodları
│ │ │ └── com/example/
│ │ │ └── App.java
│ │ └── resources/ ← Kaynak dosyalar (config, xml...)
│ └── test/
│ ├── java/ ← Test kodları
│ │ └── com/example/
│ │ └── AppTest.java
│ └── resources/ ← Test kaynak dosyaları
└── target/ ← Derleme çıktıları (Maven oluşturur)Bu yapı her Maven projesinde aynı. Bir Maven projesini ilk kez açsan bile nereye bakacağını bilirsin. Kaynak kodlar src/main/java, testler src/test/java, çıktılar target/ altında.
pom.xml — Projenin Kalbi
POM (Project Object Model) dosyası, Maven'a projenin ne olduğunu, neye bağımlı olduğunu ve nasıl build edileceğini anlatan XML dosyasıdır. Her Maven projesinin kök dizininde bir pom.xml bulunur.
İşte basit bir pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>Buradaki anahtar kavramları tek tek açıklayalım:
GAV Koordinatları (groupId, artifactId, version): Her Maven artifact'i bu üç değerle benzersiz olarak tanımlanır. Bunu bir kargo adresi gibi düşün: groupId şehir, artifactId sokak, version kapı numarası. com.google.code.gson:gson:2.10.1 dediğinde dünyadaki tek bir kütüphaneyi göstermiş olursun.
packaging: Çıktı formatı. jar (varsayılan), war (web uygulaması), pom (sadece parent tanımı) olabilir.
properties: Tekrar eden değerleri merkezi bir yerde tanımlarsın. Java versiyonu, encoding gibi ayarlar buraya.
dependencies: Projenin ihtiyaç duyduğu kütüphaneler. Maven bunları otomatik indirir.
scope: Dependency'nin nerede kullanılacağını belirtir:
compile(varsayılan): Her yerde kullanılır, JAR'a dahil edilirtest: Sadece test kodlarında kullanılırprovided: Derleme zamanında var, runtime'da sunucu sağlar (ör: Servlet API)runtime: Derleme zamanında gereksiz, runtime'da lazım (ör: JDBC driver)
3. Maven Lifecycle — Build Adımları
Maven'ın en güçlü yanlarından biri standart lifecycle (yaşam döngüsü) kavramıdır. Her Maven komutu belirli bir sırayla adımları çalıştırır. Bir adımı çağırdığında, ondan önceki tüm adımlar da otomatik çalışır.
Varsayılan lifecycle şu adımlardan oluşur:
validate → compile → test → package → verify → install → deploy| Komut | Ne Yapar |
|---|---|
mvn clean | target/ dizinini siler (temiz başlangıç) |
mvn compile | Kaynak kodları derler |
mvn test | Testleri çalıştırır (önce compile eder) |
mvn package | JAR/WAR oluşturur (önce test eder) |
mvn install | JAR'ı lokal repo'ya koyar (~/.m2/) |
mvn deploy | JAR'ı uzak repo'ya yükler (Nexus, Artifactory) |
En sık kullanacağın komutlar:
# Temiz build — her şeyi silip sıfırdan
mvn clean package
# Testleri atlayarak hızlı paketleme
mvn clean package -DskipTests
# Sadece derleme (testleri çalıştırmaz)
mvn compile
# Sadece testleri çalıştır
mvn test⚠️ Dikkat:
mvn packagedediğinde Maven sıraylavalidate → compile → test → packageadımlarının hepsini çalıştırır. Yani testlerin geçmezse paket oluşmaz! Production'a göndermeden önce testlerin geçtiğinden emin ol.
Lifecycle Faz Sıralaması Önemli
Bu sıralama çok önemli bir sonuç doğurur: herhangi bir fazı çalıştırdığında, önceki tüm fazlar zaten çalışmış olur. mvn install dediğinde compile, test ve package hepsi zaten yapılır. Yani ayrı ayrı çağırmana gerek yok.
4. Maven'da Dependency Yönetimi
Maven'ın en büyük kolaylığı dependency yönetimidir. İhtiyacın olan kütüphaneyi pom.xml'e eklersin, Maven onu Maven Central deposundan otomatik indirir.
Maven Central'dan Dependency Bulma
https://search.maven.org veya https://mvnrepository.com adreslerinden kütüphane arayabilirsin. Örneğin "jackson json" diye aratırsan Jackson kütüphanesinin GAV koordinatlarını bulursun.
Transitive Dependency
Maven'ın gerçek gücü burada ortaya çıkar. Diyelim Spring Boot'a bağımlısın. Spring Boot da kendi içinde 20+ kütüphaneye bağımlı. Sen sadece Spring Boot'u eklersin, Maven geri kalan her şeyi otomatik indirir.
<!-- Sen sadece bunu eklersin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.2</version>
</dependency>
<!-- Maven arka planda Tomcat, Jackson, Spring MVC,
Spring Core... hepsini indirir -->Hangi bağımlılıkların indirildiğini görmek için:
mvn dependency:treeBu komut, projenin tüm dependency ağacını gösterir. Versiyon çakışmalarını tespit etmek için çok işe yarar.
Dependency Çakışması (Conflict)
İki farklı kütüphane aynı alt-kütüphanenin farklı versiyonlarını isteyebilir. Maven bu durumda "nearest wins" (en yakın kazanır) kuralını uygular — dependency ağacında sana en yakın olan versiyon kullanılır.
Belirli bir versiyonu zorlamak istersen <dependencyManagement> bloğunu kullanabilirsin:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>
</dependencies>
</dependencyManagement>Bu blok, projenin her yerinde bu kütüphanenin belirtilen versiyonunu kullanılmasını garanti eder.
5. Maven Plugin'leri
Maven'ın tüm işlevleri aslında plugin'ler tarafından sağlanır. compile fazı maven-compiler-plugin, test fazı maven-surefire-plugin tarafından yürütülür. Kendi plugin'lerini de ekleyebilirsin.
Sık kullanılan plugin'ler:
<build>
<plugins>
<!-- Çalıştırılabilir JAR oluşturmak -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<transformers>
<transformer implementation=
"org.apache.maven.plugins.shade.resource
.ManifestResourceTransformer">
<mainClass>com.example.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<!-- Java versiyonunu belirle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.12.1</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>maven-shade-plugin: Tüm bağımlılıkları tek bir "fat JAR" içinde toplar. java -jar app.jar diyerek doğrudan çalıştırabilirsin.
maven-compiler-plugin: Derleme ayarlarını kontrol eder. Java versiyonu, encoding, derleyici parametreleri burada.
6. Gradle — Modern ve Esnek Alternatif
Gradle, 2012'de ortaya çıkan ve özellikle Android geliştirmede standart olan modern build aracıdır. Maven'ın XML tabanlı yaklaşımı yerine programlanabilir bir build script kullanır.
Maven vs Gradle — İlk İzlenim
Maven'da her şey XML. Gradle'da ise Groovy veya Kotlin ile yazılmış bir script var. Bu fark ilk başta kozmetik gibi görünür ama pratik sonuçları büyüktür:
<!-- Maven: 8 satır bir dependency eklemek için -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>// Gradle (Groovy DSL): 1 satır
implementation 'com.google.code.gson:gson:2.10.1'// Gradle (Kotlin DSL): 1 satır
implementation("com.google.code.gson:gson:2.10.1")Gradle Proje Yapısı
Gradle'ın dizin yapısı Maven ile neredeyse aynıdır (src/main/java, src/test/java). Fark, konfigürasyon dosyalarında:
my-project/
├── build.gradle ← Groovy DSL (veya build.gradle.kts → Kotlin DSL)
├── settings.gradle ← Proje adı, multi-module ayarları
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew ← Linux/Mac wrapper script
├── gradlew.bat ← Windows wrapper script
└── src/
├── main/java/
└── test/java/Gradle Wrapper (`gradlew`): Gradle'ın en zekice özelliklerinden biri. Projeyle birlikte gelen bu script, doğru Gradle versiyonunu otomatik indirir ve kullanır. Yani sisteme Gradle kurman gerekmez — ./gradlew build deyip geçersin.
build.gradle — Temel Yapı
Groovy DSL ile basit bir build dosyası:
plugins {
id 'java'
id 'application'
}
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}
application {
mainClass = 'com.example.App'
}
test {
useJUnitPlatform()
}Aynı dosyanın Kotlin DSL versiyonu (build.gradle.kts):
plugins {
java
application
}
group = "com.example"
version = "1.0.0"
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.code.gson:gson:2.10.1")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
}
application {
mainClass.set("com.example.App")
}
tasks.test {
useJUnitPlatform()
}💡 İpucu: Yeni projelerde Kotlin DSL (
.kts) tercih et. IDE desteği çok daha iyi — otomatik tamamlama, hata kontrolü, refactoring hepsi çalışıyor. Groovy DSL'de IDE "bu bir String mi yoksa closure mı?" diye çoğu zaman şaşırır.
Gradle Task'ları
Gradle'ın temel birimi task (görev). Her build adımı bir task. Maven lifecycle'ından farklı olarak, Gradle'da kendi task'larını kolayca tanımlayabilirsin:
# Derleme
./gradlew build
# Sadece test
./gradlew test
# Temiz build
./gradlew clean build
# Uygulamayı çalıştır (application plugin)
./gradlew run
# Mevcut task'ları listele
./gradlew tasksKendi task'ını tanımlamak:
tasks.register('hello') {
doLast {
println 'Merhaba, Gradle!'
}
}
// Çalıştır: ./gradlew helloGroovy DSL vs Kotlin DSL
| Özellik | Groovy DSL | Kotlin DSL |
|---|---|---|
| Dosya | build.gradle | build.gradle.kts |
| Söz dizimi | Dinamik, esnek | Tip-güvenli, katı |
| IDE desteği | Orta | Mükemmel |
| Öğrenme eğrisi | Kolay | Orta |
| Hata yakalama | Runtime | Compile-time |
| Yeni projelerde | Azalıyor | Artıyor |
7. Dependency Konfigürasyonları — Gradle'da Scope
Maven'daki scope kavramının Gradle karşılıkları:
| Maven Scope | Gradle Konfigürasyonu | Açıklama |
|---|---|---|
compile | implementation | Ana bağımlılık |
compile (API) | api | Bağımlılığı tüketicilere açar |
test | testImplementation | Sadece test |
provided | compileOnly | Derleme zamanı, runtime'da yok |
runtime | runtimeOnly | Sadece runtime |
`implementation` vs `api` farkı önemli: implementation ile eklediğin dependency, seni kullanan projeye sızmaz. api ise sızar. Kütüphane yazıyorsan bu ayrım kritik — mümkünse implementation kullan, derleme süresini kısaltır.
8. Maven Central'dan Dependency Ekleme — Pratik Örnek
Diyelim bir JSON işleme projesi yapıyorsun ve Jackson kütüphanesine ihtiyacın var.
Adım 1: https://mvnrepository.com adresine git ve "jackson-databind" ara.
Adım 2: Doğru versiyonu seç (genelde en güncel stable versiyonu).
Adım 3: pom.xml'e veya build.gradle'a ekle:
Maven:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>Gradle:
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'Adım 4: IDE'de "Reload" veya terminalde mvn compile / ./gradlew build çalıştır.
Bu kadar. Artık Jackson'ı kodunda kullanabilirsin:
import com.fasterxml.jackson.databind.ObjectMapper;
class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
// Object → JSON
var user = new User("Ali", 25);
String json = mapper.writeValueAsString(user);
System.out.println(json);
// {"name":"Ali","age":25}
// JSON → Object
User parsed = mapper.readValue(json, User.class);
System.out.println(parsed.name()); // Ali
}
record User(String name, int age) {}
}9. Multi-Module Proje Yapısı
Büyük projelerde kodu modüllere ayırmak gerekir. Örneğin bir e-ticaret uygulamasında core, api, web, common gibi modüller olabilir.
Maven Multi-Module
Üst dizinde bir parent pom.xml, her modülde kendi pom.xml'i bulunur:
<!-- Parent pom.xml -->
<project>
<groupId>com.example</groupId>
<artifactId>ecommerce</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>core</module>
<module>api</module>
</modules>
<dependencyManagement>
<dependencies>
<!-- Tüm modüllerin kullanacağı versiyonları belirle -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>Alt modüller parent'a referans verir:
<!-- common/pom.xml -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>ecommerce</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>common</artifactId>
<dependencies>
<!-- Versiyonu parent'tan alır -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
</project>Gradle Multi-Module
// settings.gradle
rootProject.name = 'ecommerce'
include 'common', 'core', 'api'// core/build.gradle
plugins { id 'java' }
dependencies {
implementation project(':common') // modüller arası bağımlılık
}Gradle'da modüller arası bağımlılık project(':modül-adı') ile tanımlanır. Maven'a göre çok daha az boilerplate.
10. Maven vs Gradle — Kapsamlı Karşılaştırma
| Kriter | Maven | Gradle |
|---|---|---|
| Konfigürasyon | XML (pom.xml) | Groovy/Kotlin (build.gradle) |
| Öğrenme eğrisi | Kolay — kuralları takip et | Orta — programlama bilgisi gerekir |
| Esneklik | Düşük — convention-based | Yüksek — her şey özelleştirilebilir |
| Performans | Orta | Yüksek (incremental build, cache) |
| Ekosistem | Çok geniş, matür | Büyüyen, Android'de standart |
| IDE desteği | Mükemmel | Mükemmel |
| CI/CD entegrasyonu | Her yerde desteklenir | Her yerde desteklenir |
| Multi-module | İyi ama verbose | Çok temiz ve kolay |
| Kurumsal kullanım | Bankalar, büyük şirketler | Startup'lar, Android, modern projeler |
Hangisini Seçmeli?
Maven seç eğer:
Ekibin Maven'a alışıksa
Kurumsal bir ortamda çalışıyorsan
Basit, standart bir proje yapısı istiyorsan
Spring Boot projesi yapıyorsan (ikisi de iyi ama Maven daha yaygın)
Gradle seç eğer:
Android geliştirme yapıyorsan (zorunlu)
Çok modüllü, karmaşık build senaryolarin varsa
Build performansı kritikse (büyük projelerde Gradle 2-3x hızlı olabilir)
Build script'inde programlama esnekliği istiyorsan
💡 İpucu: İlk kez build aracı öğreniyorsan Maven ile başla. Kavramlar daha net, community kaynakları daha bol. Maven'ı anladıktan sonra Gradle'a geçiş çok kolay. Tersi biraz daha zor çünkü Gradle'ın esnekliği başlangıçta kafa karıştırıcı olabilir.
11. Gerçek Dünya Senaryosu — Proje Oluşturma
Maven ile sıfırdan proje oluşturmak:
# Maven archetype ile proje oluştur
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=my-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false
cd my-app
mvn clean package
java -jar target/my-app-1.0-SNAPSHOT.jarGradle ile sıfırdan proje oluşturmak:
# Gradle init ile proje oluştur
mkdir my-app && cd my-app
gradle init --type java-application \
--dsl kotlin \
--test-framework junit-jupiter \
--project-name my-app
./gradlew runHer iki araç da IDE'ler (IntelliJ IDEA, Eclipse, VS Code) tarafından mükemmel desteklenir. IntelliJ'de "New Project" diyerek hem Maven hem Gradle projesi oluşturabilirsin — hiç terminal kullanmana gerek kalmaz.
12. Yaygın Hatalar ve Çözümleri
"Could not find artifact" Hatası
Maven dependency bulamıyorsa:
GAV koordinatlarını kontrol et (typo var mı?)
repositoriesbloğunda Maven Central tanımlı mı?İnternet bağlantını kontrol et
mvn clean install -Uile cache'i zorla güncelle
"Build is using deprecated features" Uyarısı
Java versiyonu ayarlarını kontrol et. properties bloğunda doğru versiyonu belirttiğinden emin ol.
Gradle Wrapper Versiyonu Sorunu
# Wrapper versiyonunu güncelle
./gradlew wrapper --gradle-version 8.5⚠️ Dikkat: Üretim projesinde build aracı versiyonunu rastgele değiştirme. Tüm ekibin aynı versiyonu kullandığından emin ol. Maven Wrapper (
mvnw) veya Gradle Wrapper (gradlew) bu sorunu çözer — wrapper dosyalarını versiyon kontrolüne (Git) dahil et.
13. Build Aracı Olmadan Hayat — Neden Kaçınılmaz?
Bir an için build aracı olmadan bir Java projesi düşünelim:
# 3 dış kütüphane ile basit bir proje — elle derleme
javac -cp gson-2.10.1.jar:jackson-databind-2.16.1.jar:slf4j-api-2.0.9.jar \
-d out/ \
src/com/example/*.java
# Ama jackson-databind, jackson-core ve jackson-annotations'a da bağımlı!
# Onları da indirip classpath'e eklemelisin...
# Ve her birinin doğru versiyonunu bulmalısın...
# Ve testleri ayrıca çalıştırmalısın...
# Ve JAR'ı elle paketlemelisin...Gördüğün gibi, 3 kütüphane bile elle yönetilmesi kabus olan bir ortam yaratıyor. Build araçları bu karmaşıklığı bir pom.xml veya build.gradle dosyasına indirgeyerek hayatını kurtarır.
Özet
Build araçları, Java projelerinde derleme, bağımlılık yönetimi, test ve paketleme işlemlerini otomatikleştirir — gerçek dünyada
javacile elle derleme yapılmaz.Maven, XML tabanlı, "convention over configuration" felsefesiyle çalışan, sektörde en yaygın Java build aracıdır.
pom.xmldosyası projenin kalbidir.Maven Lifecycle adımları (compile → test → package → install) sıralı çalışır; bir adımı çağırdığında öncekiler otomatik koşulur.
Gradle, Groovy veya Kotlin DSL ile programlanabilir build script'leri sunar. Daha esnek, daha hızlı (incremental build) ve Android'de standart build aracıdır.
Dependency yönetimi her iki araçta da otomatiktir — kütüphaneyi tanımlarsın, transitive bağımlılıklarıyla birlikte indirilir.
İlk kez öğreniyorsan Maven ile başla, kavramları oturt; sonra Gradle'a geçiş çok kolay olur. Hangisini seçersen seç, build aracı olmadan ciddi Java projesi yapmak mümkün değildir.
AI Asistan
Sorularını yanıtlamaya hazır