Eğitim Portalı/Spring vs Boot/Spring ve Spring Boot: Temel Farklar
Spring vs Boot04-spring-vs-spring-boot/00-temel-farklar

Spring ve Spring Boot: Temel Farklar

Bu eğitimde önce Spring Framework'ün çekirdeğini, sonra Spring Boot'u öğrendik. Şimdi ikisini yan yana koyup farkı net görelim — çünkü "Spring mi Spring Boot mu?" sorusu yeni başlayanların en sık karıştırdığı konudur.…

Spring ve Spring Boot: Temel Farklar

Bu eğitimde önce Spring Framework'ün çekirdeğini, sonra Spring Boot'u öğrendik. Şimdi ikisini yan yana koyup farkı net görelim — çünkü "Spring mi Spring Boot mu?" sorusu yeni başlayanların en sık karıştırdığı konudur. Kısa cevap: rakip değiller; Spring Boot, Spring'in üzerine kurulu bir kolaylık katmanıdır. Aynı işi her ikisiyle de yapıp aradaki farkı somutlaştıracağız.

İlişki: rakip değil, katman

  • Spring Framework, temel yapı taşlarını sağlar: IoC container, DI, AOP, web (MVC), veri erişimi, güvenlik. Güçlüdür ama bu parçaları sen birleştirir, yapılandırır, sürümlerini uyumlar ve (web ise) bir sunucu kurarsın.
  • Spring Boot, Spring'in üzerine oturur ve kurulum yükünü neredeyse sıfıra indirir: otomatik yapılandırma, starter bağımlılıkları, gömülü sunucu, üretim araçları.

Spring Boot'u kullanırken hâlâ Spring'i kullanıyorsun. Boot sadece "tekrar eden kurulum kararlarını" senin yerine, makul varsayılanlarla veriyor.

Aynı iş, iki yöntem

Bu farkı en iyi, aynı görevi her ikisiyle yaparak görürsün. Görev: bir H2 veritabanına bağlanıp ürün kaydetmek.

Düz Spring (Örnek 1, ./Ornek1.java): Her şeyi elle yapılandırırsın — ApplicationContext'i kur, DataSource'u tanımla, JdbcTemplate'i oluştur, bean'leri bağla:

@Bean DataSource dataSource() { /* sürücü, URL, kullanıcı elle */ }
@Bean JdbcTemplate jdbcTemplate(DataSource ds) { return new JdbcTemplate(ds); }

Spring Boot (Örnek 2, ./Ornek2.java): DataSource veya JdbcTemplate tanımlamazsın; Boot, classpath'te H2 + spring-jdbc görüp ikisini de otomatik kurar. Sen sadece enjekte edip kullanırsın:

CommandLineRunner selfTest(JdbcTemplate jdbc) { /* doğrudan kullan */ }

Aynı sonuç, çok daha az kod. Örnek 3 (./Ornek3.java) bunu sayılarla gösterir: birkaç satır kod yazarsın ama container'da yüzlerce bean (Tomcat, Jackson, DataSource, JPA...) otomatik oluşturulur — üstelik çalışan bir web sunucun olur, hiç sunucu kurmadan.

Karşılaştırma tablosu

KonuSpring FrameworkSpring Boot
YapılandırmaManuel (XML/Java config)Otomatik (auto-configuration)
BağımlılıklarTek tek seç + sürüm uyumlaStarter'lar (uyumlu set)
SunucuHarici Tomcat kur/yapılandırGömülü (jar içinde)
ÇalıştırmaWAR + sunucujava -jar
BaşlangıçÇok kurulumstart.spring.io → dakikalar
VarsayılanlarSen verirsinMakul varsayılanlar hazır
Üretim araçlarıElle ekleActuator vb. hazır
EsneklikTam kontrolVarsayılanları geçersiz kılabilirsin

"Sihir" değil, akıllı varsayılanlar

Spring Boot'un otomatik yapılandırması sihir değildir: classpath'e bakar (@ConditionalOnClass, @ConditionalOnMissingBean gibi koşullarla) ve "H2 var ama DataSource tanımlı değilse, bir H2 DataSource kur" gibi kararlar verir. Sen kendi bean'ini tanımladığın an, Boot geri çekilir (senin tanımın kazanır). Yani kontrol her zaman sende kalır; Boot sadece sen susunca makul olanı yapar.

Özet

Spring ve Spring Boot'un rakip değil, katman ilişkisinde olduğunu; aynı işi düz Spring'de elle (Örnek 1), Boot'ta otomatik (Örnek 2) yaptığımızı ve Boot'un ne kadar altyapıyı üstlendiğini (Örnek 3) gördük. Bir sonraki konuda kararı netleştiriyoruz: hangi durumda hangisini seçmeli ve düz Spring'den Boot'a nasıl geçilir?

Kod Örnekleri(3)

Ornek1

ortam gerekir
Ornek1.java
1// Ornek1: DÜZ SPRING (Boot YOK) — her şeyi ELLE yapılandırırız.
2// Aynı işi Örnek 2'de Spring Boot ile yapıp farkı göreceğiz.
3// Çalıştırma: portal Spring + H2 classpath'iyle çalıştırır.
4import org.springframework.context.annotation.AnnotationConfigApplicationContext;
5import org.springframework.context.annotation.Bean;
6import org.springframework.context.annotation.Configuration;
7import org.springframework.jdbc.core.JdbcTemplate;
8import org.springframework.jdbc.datasource.DriverManagerDataSource;
9
10import javax.sql.DataSource;
11
12public class Ornek1 {
13
14    public static void main(String[] args) {
15        System.out.println("================ DÜZ SPRING (manuel yapılandırma) ================");
16
17        // 1) Context'i ELLE oluştururuz.
18        var ctx = new AnnotationConfigApplicationContext(ManuelConfig.class);
19
20        // 2) Bean'i alıp kullanırız.
21        UrunServisi servis = ctx.getBean(UrunServisi.class);
22        servis.ekle("Klavye");
23        servis.ekle("Mouse");
24        System.out.println("Kayıtlı ürün sayısı: " + servis.adet());
25
26        ctx.close();
27        System.out.println("""
28
29                --- Düz Spring'de NE yaptık? ---
30                - ApplicationContext'i elle kurduk.
31                - DataSource'u (sürücü, URL, kullanıcı) elle tanımladık.
32                - JdbcTemplate bean'ini elle oluşturduk.
33                - Sürücü/sürüm uyumunu, sunucuyu (web olsaydı) elle yönetirdik.
34                Çok kontrol var ama çok da boilerplate. Örnek 2'de Boot bunların çoğunu siler.""");
35    }
36
37    @Configuration
38    static class ManuelConfig {
39        // DataSource'u ELLE tanımlıyoruz (Boot bunu classpath'e bakıp otomatik yapardı).
40        @Bean
41        DataSource dataSource() {
42            var ds = new DriverManagerDataSource("jdbc:h2:mem:duz;DB_CLOSE_DELAY=-1", "sa", "");
43            ds.setDriverClassName("org.h2.Driver");
44            return ds;
45        }
46
47        // JdbcTemplate'i ELLE oluşturuyoruz.
48        @Bean
49        JdbcTemplate jdbcTemplate(DataSource ds) { return new JdbcTemplate(ds); }
50
51        @Bean
52        UrunServisi urunServisi(JdbcTemplate jdbc) { return new UrunServisi(jdbc); }
53    }
54
55    static class UrunServisi {
56        private final JdbcTemplate jdbc;
57        UrunServisi(JdbcTemplate jdbc) {
58            this.jdbc = jdbc;
59            jdbc.execute("CREATE TABLE urun (ad VARCHAR(50))");
60        }
61        void ekle(String ad) { jdbc.update("INSERT INTO urun VALUES (?)", ad); }
62        int adet() { return jdbc.queryForObject("SELECT COUNT(*) FROM urun", Integer.class); }
63    }
64}
canlı çalıştırma için ortam gerekir

Bu örnek Spring / Spring Boot (Gradle) ortamı gerektirir; tek dosya olarak java Ornek1.java ile çalışmaz. Orijinal portal bunu gömülü Tomcat / Spring context ile koşuyordu. Beklenen davranış yukarıdaki anlatım ve kodda açıklanmıştır.

Ornek2

ortam gerekir
Ornek2.java
1// Ornek2: SPRING BOOT — aynı veri işi, ama DataSource ve veri katmanı OTOMATİK gelir.
2// Sen yalnızca @Entity ve JpaRepository arayüzünü yazarsın; gerisini Boot yapar.
3// Çalıştırma: portal derleyip gömülü Tomcat + H2 ile başlatır.
4package com.egitim.karsilastirma;
5
6import jakarta.persistence.Entity;
7import jakarta.persistence.GeneratedValue;
8import jakarta.persistence.GenerationType;
9import jakarta.persistence.Id;
10import org.springframework.boot.CommandLineRunner;
11import org.springframework.boot.SpringApplication;
12import org.springframework.boot.autoconfigure.SpringBootApplication;
13import org.springframework.context.annotation.Bean;
14import org.springframework.data.jpa.repository.JpaRepository;
15
16@SpringBootApplication
17public class Ornek2 {
18
19    public static void main(String[] args) { SpringApplication.run(Ornek2.class, args); }
20
21    // DİKKAT: DataSource, EntityManager, transaction yöneticisi... HİÇBİRİNİ tanımlamadık.
22    // Boot, classpath'te H2 + Spring Data JPA görüp bunların HEPSİNİ otomatik yapılandırır.
23    // Bizim yazdığımız tek şey: bir @Entity ve bir repository ARAYÜZÜ.
24    @Bean
25    CommandLineRunner selfTest(UrunRepo repo) {
26        return args -> {
27            System.out.println("\n================ SPRING BOOT (otomatik yapılandırma) ================");
28            repo.save(new Urun("Klavye"));
29            repo.save(new Urun("Mouse"));
30            System.out.println("Kayıtlı ürün sayısı: " + repo.count());
31            System.out.println("Ürünler: " + repo.findAll().stream().map(Urun::getAd).toList());
32            System.out.println("""
33
34                    --- Spring Boot'ta NE yapmadık? ---
35                    - DataSource TANIMLAMADIK (Boot H2'yi görüp otomatik kurdu).
36                    - EntityManager / transaction yöneticisi TANIMLAMADIK (otomatik geldi).
37                    - Repository implementasyonu YAZMADIK (Spring Data üretti).
38                    Sadece bir @Entity + bir arayüz yazdık. İşte Boot'un 'convention over configuration' farkı.""");
39        };
40    }
41}
42
43@Entity
44class Urun {
45    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
46    private Long id;
47    private String ad;
48    protected Urun() {}
49    Urun(String ad) { this.ad = ad; }
50    String getAd() { return ad; }
51}
52
53interface UrunRepo extends JpaRepository<Urun, Long> {}
canlı çalıştırma için ortam gerekir

Bu örnek Spring / Spring Boot (Gradle) ortamı gerektirir; tek dosya olarak java Ornek2.java ile çalışmaz. Orijinal portal bunu gömülü Tomcat / Spring context ile koşuyordu. Beklenen davranış yukarıdaki anlatım ve kodda açıklanmıştır.

Ornek3

ortam gerekir
Ornek3.java
1// Ornek3: Boot'un "sihrini" sayılarla görmek — otomatik yapılandırmanın ölçeği.
2// Çalıştırma: portal derleyip gömülü Tomcat ile başlatır.
3package com.egitim.karsilastirma;
4
5import org.springframework.boot.CommandLineRunner;
6import org.springframework.boot.SpringApplication;
7import org.springframework.boot.autoconfigure.SpringBootApplication;
8import org.springframework.context.ApplicationContext;
9import org.springframework.context.annotation.Bean;
10import org.springframework.web.bind.annotation.GetMapping;
11import org.springframework.web.bind.annotation.RestController;
12import org.springframework.web.client.RestClient;
13
14@SpringBootApplication
15public class Ornek3 {
16
17    public static void main(String[] args) { SpringApplication.run(Ornek3.class, args); }
18
19    // Yazdığımız TEK kod: küçük bir controller.
20    @RestController
21    static class SelamController {
22        @GetMapping("/selam") String selam() { return "merhaba"; }
23    }
24
25    @Bean
26    CommandLineRunner selfTest(ApplicationContext ctx) {
27        return args -> {
28            System.out.println("\n================ BOOT'UN SİHRİ (sayılarla) ================");
29            // Bizim yazdığımız: 1 controller + 1 runner. Geri kalan her şey otomatik.
30            System.out.println("Container'daki TOPLAM bean sayısı: " + ctx.getBeanDefinitionCount());
31            System.out.println("(Tomcat, DispatcherServlet, Jackson, DataSource, JdbcTemplate, JPA,");
32            System.out.println(" hata yönetimi, metrikler... yüzlerce bean OTOMATİK yapılandırıldı.)");
33
34            // Üstelik çalışan bir web sunucumuz var — hiç sunucu kurmadan:
35            RestClient c = RestClient.create("http://localhost:8080");
36            System.out.println("\nGET /selam -> " + c.get().uri("/selam").retrieve().body(String.class));
37
38            System.out.println("""
39                    ==========================================================
40                    Düz Spring'de bunların HEPSİNİ elle yapılandırman gerekirdi:
41                      sunucu, servlet, JSON dönüştürücü, veri kaynağı, sürüm uyumu...
42                    Spring Boot, classpath'e bakıp makul varsayılanlarla bunları otomatik kurar.
43                    Sen iş mantığına odaklanırsın; altyapı Boot'un işidir.""");
44        };
45    }
46}
canlı çalıştırma için ortam gerekir

Bu örnek Spring / Spring Boot (Gradle) ortamı gerektirir; tek dosya olarak java Ornek3.java ile çalışmaz. Orijinal portal bunu gömülü Tomcat / Spring context ile koşuyordu. Beklenen davranış yukarıdaki anlatım ve kodda açıklanmıştır.