100 adımda Spring Boot öğrenmek ve uygulama geliştirmek için temel adımları içeren bir rehber:




İşte 100 adımda Spring Boot öğrenmek ve uygulama geliştirmek için temel adımları içeren bir rehber:


1. Spring Boot Nedir?

  • Spring Boot, Spring çerçevesinin hızlı ve kolay kullanımı için geliştirilmiş bir yapılandırma aracıdır. Minimal konfigürasyonla mikroservisler oluşturmanıza olanak tanır.


  • Spring Boot, Spring Framework'ün hızlandırılmış ve basitleştirilmiş bir versiyonudur. Geliştiricilere minimal konfigürasyon gereksinimiyle, hızlı bir şekilde bağımsız, üretim seviyesinde Spring tabanlı uygulamalar geliştirme olanağı sağlar. Geleneksel Spring uygulamalarında birçok XML tabanlı yapılandırma gerekiyorken, Spring Boot, varsayılan ayarları kullanarak bu karmaşıklığı azaltır.


Spring Boot’un Sağladığı Avantajlar:

  1. Kolay Konfigürasyon: Varsayılan ayarlar ve otomatik yapılandırmalar sayesinde minimum manuel konfigürasyon.
  2. Yerleşik Sunucu: Tomcat, Jetty veya Undertow gibi yerleşik sunucularla uygulamanızı dış bir sunucuya deploy etmeden çalıştırabilirsiniz.
  3. Hızlı Başlangıç: Spring Initializr gibi araçlar sayesinde hızlıca proje oluşturabilir ve çalıştırabilirsiniz.
  4. Mikroservis Mimarisine Uyum: Mikroservis mimarisi için idealdir, dağıtık sistemler kurmaya uygundur.
  5. Üretim Seviyesi Hazırlık: Actuator, güvenlik ve kolay konfigürasyon seçenekleriyle üretim ortamı için güçlü bir altyapı sağlar.


Spring Boot, kompleks Spring uygulamalarının temellerini basitleştirerek hız ve verimlilik sağlar, bu da mikroservis ve bulut tabanlı çözümler için oldukça uygundur.


2. Proje Kurulumu - Spring Initializr

  • Spring Initializr (https://start.spring.io/) kullanarak proje oluşturun.
  • Maven ya da Gradle seçimi yapın. Grup, proje adı gibi bilgileri doldurun.
  • Bağımlılık olarak: Spring Web, Spring Data JPA, H2 Database vb. seçin.
  • Proje Kurulumu - Spring Initializr


  • Spring Initializr'ı Kullanarak Proje Oluşturma:

    • Spring Initializr (https://start.spring.io/) üzerinden Spring Boot projesi oluşturabilirsiniz.
    • Burada grup adı (Group), proje adı (Artifact), proje açıklaması (Description), ve paket adı (Package Name) gibi bilgileri girerek temel proje ayarlarını yapabilirsiniz.


  • Maven veya Gradle Seçimi:
    • Maven ya da Gradle gibi build araçlarını seçin. Maven, daha yaygın kullanılan bir araçtır, ancak Gradle daha esnek ve performanslıdır. Tercihinize göre birini seçebilirsiniz.


  • Spring Boot Versiyonu:
    • Projeyi oluştururken kullanmak istediğiniz Spring Boot versiyonunu seçin. Genelde en son kararlı sürümü seçmek iyi bir tercihtir.


  • Bağımlılıklar (Dependencies):
    • Projeniz için gerekli olan Spring Boot modüllerini ekleyin. Mikroservis, web tabanlı bir uygulama ya da veri tabanı işlemleri yapacaksanız aşağıdaki bağımlılıkları seçebilirsiniz:
      • Spring Web: Web uygulamaları geliştirmek için gerekli bağımlılık. RESTful API'ler oluşturmak için kullanılır.
      • Spring Data JPA: Veri tabanı işlemleri ve JPA (Java Persistence API) entegrasyonu için kullanılır.
      • H2 Database: Hafif, yerleşik bir veri tabanı. Geliştirme ve test amaçlı kullanılır.
      • Spring Boot DevTools: Geliştirme sürecinde uygulamanın otomatik yeniden başlatılması ve hızlı gelişim için devtools modülünü ekleyebilirsiniz.


  • Projeyi İndirin ve Çalıştırın:
    • Bilgileri doldurduktan sonra “Generate” butonuna tıklayarak projeyi indirin.
    • İndirdiğiniz ZIP dosyasını açın ve IDE'nize (IntelliJ IDEA, Eclipse vb.) aktarın.
    • Maven ya da Gradle kullanıyorsanız, projenizin bağımlılıklarını indirip yapılandırın.


  • Proje Başlatma:
    • Main sınıfını çalıştırarak Spring Boot uygulamanızı başlatabilirsiniz. @SpringBootApplication anotasyonu ile uygulamanız otomatik olarak başlatılır.


Örnek Maven Bağımlılıkları (pom.xml):



<dependencies>

    <!-- Spring Web Starter -->

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-web</artifactId>

    </dependency>


    <!-- Spring Data JPA -->

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-data-jpa</artifactId>

    </dependency>


    <!-- H2 Database -->

    <dependency>

        <groupId>com.h2database</groupId>

        <artifactId>h2</artifactId>

        <scope>runtime</scope>

    </dependency>


    <!-- Spring Boot DevTools -->

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-devtools</artifactId>

        <scope>runtime</scope>

        <optional>true</optional>

    </dependency>


    <!-- Spring Boot Test -->

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-test</artifactId>

        <scope>test</scope>

    </dependency>

</dependencies>



Bu adımları tamamladıktan sonra Spring Boot projeniz çalışmaya hazır olacaktır!


3. Spring Boot Ana Sınıfı

  • 3. Spring Boot Ana Sınıfı


  • Spring Boot uygulamalarında, ana sınıf uygulamanın giriş noktasıdır ve @SpringBootApplication anotasyonu ile tanımlanır. Bu anotasyon, bir Spring Boot uygulamasını başlatmak için gereken yapılandırmaları otomatik olarak sağlar.


@SpringBootApplication Anotasyonu:

  1. @SpringBootApplication, üç önemli anotasyonu bir araya getirir:
    1. @Configuration: Uygulamanın yapılandırmasını belirtir ve Spring IoC container'a bean'leri tanıtır.
    2. @EnableAutoConfiguration: Spring Boot'un otomatik yapılandırma özelliğini etkinleştirir, yani projenizdeki bağımlılıklara göre varsayılan konfigürasyonları yükler.
    3. @ComponentScan: Projedeki bileşenlerin (controller, service, repository gibi) taranmasını ve Spring container'a eklenmesini sağlar.


Spring Boot Ana Sınıfı Nasıl Oluşturulur:


  • Aşağıdaki kod örneği, bir Spring Boot uygulamasının ana sınıfını gösterir. Uygulamanızın başladığı yer burasıdır ve SpringApplication.run() metodu ile Spring konteyner'ını başlatarak uygulamayı çalıştırır.


Örnek Spring Boot Ana Sınıfı:



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication

public class DemoApplication {


    public static void main(String[] args) {

        SpringApplication.run(DemoApplication.class, args);

    }

}



Açıklamalar:

  1. @SpringBootApplication: Bu anotasyon sayesinde Spring Boot, uygulamanızın ana yapılandırmasını otomatik olarak başlatır.
  2. main() metodu: Bu metot Java uygulamalarında giriş noktasıdır. SpringApplication.run() metodu ile Spring Boot uygulaması başlatılır. Bu metot uygulamanızın tüm bileşenlerini (controller, service, repository gibi) çalıştırır.
  3. DemoApplication sınıfı: Ana sınıf, genellikle uygulamanızın en üst seviye yapılandırmalarını içerir. Spring Boot uygulamanızın kalbidir.


Uygulamanın Başlatılması:

  • Bu ana sınıfı çalıştırdığınızda Spring Boot, uygulamanızın temel yapılandırmalarını otomatik olarak yapar ve yerleşik bir sunucu (Tomcat gibi) üzerinde uygulamanızı çalıştırır. Uygulamanız artık http://localhost:8080 adresinde hizmet verir.


Spring Boot'un bu sade yapısı, minimal kod ile hızlı bir şekilde projeler geliştirmenizi sağlar.


4. Controller Oluşturma

  • 4. Controller Oluşturma


Spring Boot'ta Controller, gelen HTTP isteklerini karşılayan ve uygun yanıtları dönen sınıflardır. RestController sınıfı, RESTful API geliştirmede kullanılır ve HTTP isteğini karşılayıp JSON veya metin tabanlı bir yanıt döner.


@RestController ve @RequestMapping Anotasyonları:

  • @RestController: Bu anotasyon, bir sınıfın RESTful web hizmetleri için bir controller olduğunu belirtir. Yanıtlar otomatik olarak JSON, XML veya düz metin gibi uygun bir formatta döner.
  • @RequestMapping: Bu anotasyon, sınıf veya metot üzerinde kullanılarak hangi URL'lerin bu controller tarafından karşılanacağını belirtir. Hem sınıf hem de metot seviyesinde kullanılabilir.


İlk RestController Sınıfınızı Oluşturma:


Aşağıdaki örnekte, basit bir HelloController sınıfı ile "Hello, Spring Boot!" mesajını dönen bir RESTful API oluşturuyoruz.


Örnek RestController:



import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

@RequestMapping("/api")

public class HelloController {


    @GetMapping("/hello")

    public String hello() {

        return "Hello, Spring Boot!";

    }

}



Açıklamalar:

  1. @RestController: Bu sınıfın bir REST API controller'ı olduğunu belirtir. Bu sayede JSON, XML veya düz metin formatında yanıtlar döner.
  2. @RequestMapping("/api"): Tüm bu sınıftaki URL'lerin /api yolu üzerinden çalışacağını belirtir. Yani bu controller’daki tüm endpoint'ler /api ile başlar.
  3. @GetMapping("/hello"): Bu metot bir GET HTTP isteği olduğunda çalışır. URL'de /api/hello yoluna GET isteği yapıldığında, "Hello, Spring Boot!" mesajı döner.
  4. hello() metodu: Bu basit metodun döndüğü string yanıtı, kullanıcıya düz metin olarak iletilir.


Controller'ı Test Etme:

  • Uygulamanızı başlattıktan sonra, tarayıcınızda veya Postman gibi bir API test aracı kullanarak şu URL'yi ziyaret edebilirsiniz: http://localhost:8080/api/hello
  • Yanıt olarak şu mesajı görmelisiniz: Hello, Spring Boot!


Diğer HTTP Metotları:

  • @PostMapping: POST isteği için.
  • @PutMapping: PUT isteği için.
  • @DeleteMapping: DELETE isteği için.

  

Bu basit örnekle, Spring Boot'ta bir RESTful API'nin temelini nasıl oluşturacağınızı öğrendiniz.


5. Properties Dosyası (application.properties)


Spring Boot uygulamaları, yapılandırmalarını merkezi bir yerde toplamak için genellikle application.properties veya application.yml dosyalarını kullanır. Bu dosyalar, uygulamanın çeşitli ayarlarını yapılandırmanıza ve çalıştırmanıza olanak tanır. Varsayılan olarak application.properties dosyası, src/main/resources dizini altında bulunur.


application.properties Dosyasına Konfigürasyon Eklemek:


Aşağıda bir Spring Boot uygulaması için bazı temel ayarları nasıl yapılandıracağınızı gösteren örnek:



# Sunucu yapılandırması

server.port=8081  # Uygulamanın çalışacağı port numarası (varsayılan 8080)


# Veri tabanı yapılandırması (H2 Veri tabanı)

spring.datasource.url=jdbc:h2:mem:testdb  # H2 yerleşik bellek içi veri tabanı

spring.datasource.driverClassName=org.h2.Driver  # H2 veri tabanı sürücüsü

spring.datasource.username=sa  # Varsayılan kullanıcı adı

spring.datasource.password=  # Varsayılan şifre boş

spring.h2.console.enabled=true  # H2 konsolunu etkinleştirir

spring.h2.console.path=/h2-console  # H2 konsoluna erişim yolu


# Hibernate yapılandırması

spring.jpa.hibernate.ddl-auto=update  # Veri tabanı şemasını otomatik olarak günceller

spring.jpa.show-sql=true  # Konsolda SQL sorgularını gösterir



Açıklamalar:

  1. server.port=8081: Uygulamanın çalışacağı portu yapılandırır. Varsayılan port 8080'dir, ancak bunu değiştirmek için server.port kullanabilirsiniz. Bu örnekte portu 8081 olarak değiştirdik.
  2. spring.datasource.url=jdbc:h2:mem:testdb: H2 veri tabanı kullanıyorsanız, bellek içi bir veri tabanı oluşturur. Testler ve geliştirme ortamları için uygundur.
  3. spring.datasource.driverClassName=org.h2.Driver: H2 veri tabanının Java sürücüsünü belirtir.
  4. spring.datasource.username ve spring.datasource.password: Veri tabanı için kullanıcı adı ve şifre ayarlarını tanımlar. H2 için genellikle varsayılan olarak sa kullanıcı adı kullanılır ve şifre boş bırakılır.
  5. spring.h2.console.enabled=true: H2 veri tabanı için yerleşik web konsolunu etkinleştirir. Bu, veri tabanındaki tablo ve verileri tarayıcıda görüntülemenize olanak tanır.
  6. spring.h2.console.path=/h2-console: H2 konsoluna erişim yolunu belirtir. Uygulamanız çalıştığında, http://localhost:8081/h2-console adresinden erişebilirsiniz.
  7. spring.jpa.hibernate.ddl-auto=update: Bu ayar, veri tabanı şemasının otomatik olarak güncellenmesini sağlar. Geliştirme ortamı için uygundur.
    • update: Şemayı günceller ancak mevcut veriyi korur.
    • create: Her seferinde yeni bir şema oluşturur (veriler silinir).
    • validate: Şemayı kontrol eder ancak değiştirmez.
  8. spring.jpa.show-sql=true: Bu ayar, veri tabanı sorgularını konsolda görmenizi sağlar. Uygulamanızın nasıl SQL sorguları oluşturduğunu izlemek için faydalıdır.


application.properties Dosyasını Kullanma:

  • application.properties dosyasına eklenen bu ayarlar, uygulamanın davranışını değiştirir ve farklı ortamlara göre yapılandırma yapmanıza olanak tanır.
  • Uygulamanızı başlattıktan sonra http://localhost:8081/h2-console adresine giderek H2 veri tabanı konsoluna erişebilirsiniz. Veri tabanına bağlanırken jdbc:h2:mem:testdb adresini kullanabilirsiniz.


Bu yapılandırma ile Spring Boot uygulamanızın port numarasını değiştirdik, veri tabanını yapılandırdık ve SQL sorgularını takip etmeyi etkinleştirdik.

6. Yapılandırma Anotasyonları

  • @Configuration, @ComponentScan, @Bean anotasyonlarını öğrenin ve kullanın.

6. Yapılandırma Anotasyonları


Spring Boot’ta, uygulamanın yapılandırmasını sağlamak ve bağımlılıkları yönetmek için birkaç temel anotasyon kullanılır. Bu anotasyonlar, uygulamanızın modüler ve esnek olmasını sağlar. En yaygın kullanılan yapılandırma anotasyonları @Configuration, @ComponentScan, ve @Bean'dir.


1. @Configuration Anotasyonu


  • @Configuration, Spring’in IoC (Inversion of Control) konteyneri tarafından yönetilen bean’leri tanımlayan sınıfları belirtmek için kullanılır. Bu sınıf, Java tabanlı yapılandırmaların tanımlanmasını sağlar.
  • @Configuration, XML tabanlı konfigürasyon yerine Java sınıflarında yapılandırma yapılmasını sağlar.


Örnek:



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;


@Configuration

public class AppConfig {


    @Bean

    public MyService myService() {

        return new MyService();  // MyService, Spring tarafından yönetilen bir bean olacaktır

    }

}



  • Bu örnekte, AppConfig sınıfı bir konfigürasyon sınıfı olarak belirtilmiştir. İçinde bir myService adında bean tanımlanmıştır.


2. @ComponentScan Anotasyonu


  • @ComponentScan, Spring’in belirli bir paket ve onun alt paketlerinde @Component, @Service, @Repository, @Controller gibi anotasyonlar ile tanımlanan sınıfları otomatik olarak tarayıp Spring IoC konteyner'ına eklemesini sağlar.
  • Varsayılan olarak, @SpringBootApplication anotasyonu, ana sınıfın bulunduğu paketi ve alt paketlerini tarar. Ancak, uygulamanızın belirli bir paketteki bileşenleri bulmasını sağlamak için manuel olarak @ComponentScan kullanabilirsiniz.


Örnek:



import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;


@Configuration

@ComponentScan(basePackages = "com.example.services")  // Belirli bir paketi tarar

public class AppConfig {

    // Diğer konfigürasyonlar burada yer alabilir

}



  • Bu örnekte, com.example.services paketindeki tüm bileşenler taranacak ve Spring IoC konteyner'ına eklenecektir.


3. @Bean Anotasyonu


  • @Bean, Spring IoC konteynerına elle bean tanımlamak için kullanılır. @Bean metot seviyesinde kullanılır ve bir metotun geri döndüğü nesnenin Spring IoC tarafından bir bean olarak yönetileceğini belirtir.
  • @Bean anotasyonu genellikle @Configuration ile birlikte kullanılır, ancak diğer Spring bileşenleri ile de kullanılabilir.


Örnek:



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;


@Configuration

public class AppConfig {


    @Bean

    public MyService myService() {

        return new MyService();  // MyService bean olarak tanımlandı

    }


    @Bean

    public MyRepository myRepository() {

        return new MyRepository();  // MyRepository bean olarak tanımlandı

    }

}



  • Bu örnekte, myService ve myRepository Spring tarafından yönetilen bean'ler olarak tanımlanmıştır. Spring IoC bu bean'leri gerektiğinde enjekte edecektir.


Kullanım Senaryosu:

Bu anotasyonlar, Spring uygulamalarını modüler hale getirir ve yapılandırmaları yönetmeyi kolaylaştırır. @Configuration sınıfında tanımlanan @Bean'ler, uygulamanın çeşitli bileşenlerine bağımlılık enjeksiyonu ile aktarılabilir. @ComponentScan ile ise belirli bir paket ve alt paketler taranarak otomatik olarak bileşenler yüklenir.


Özet:

  • @Configuration: Java tabanlı yapılandırma sınıfı olduğunu belirtir.
  • @ComponentScan: Belirtilen paket ve alt paketlerde Spring bileşenlerini otomatik olarak tarar.
  • @Bean: Bir metot seviyesinde kullanılır ve geri döndüğü nesnenin bir Spring bean'i olacağını belirtir.


Bu yapılandırma anotasyonları, uygulamanızın daha temiz ve yapılandırılabilir olmasını sağlar.

7. Dependency Injection (Bağımlılık Enjeksiyonu)

  • 7. Dependency Injection (Bağımlılık Enjeksiyonu)


Spring Framework'ün temel özelliklerinden biri Inversion of Control (IOC) ve Dependency Injection (Bağımlılık Enjeksiyonu)'dur. Bu yaklaşım, sınıflar arasındaki bağımlılıkları Spring IoC konteyneri aracılığıyla yönetir ve gerekli sınıfların otomatik olarak enjekte edilmesini sağlar.


Bağımlılık Enjeksiyonu, bir sınıfın başka bir sınıfa olan bağımlılığını manuel olarak oluşturmak yerine, Spring tarafından otomatik olarak enjekte edilmesi anlamına gelir. Bu, kodun daha esnek, yeniden kullanılabilir ve test edilebilir olmasını sağlar.


Temel Bağımlılık Enjeksiyonu


Spring’de bağımlılık enjeksiyonunu genellikle aşağıdaki anotasyonlar aracılığıyla kullanırız:

  • @Autowired: Bağımlılıkların otomatik olarak enjekte edilmesini sağlar.
  • @Service, @Repository, @Component, @Controller: Bu anotasyonlar, sınıfları Spring IoC konteynerine tanıtarak, Spring’in bu sınıfları yönetmesini sağlar.


Örnek: @Service ve @Autowired Kullanarak Bağımlılık Enjeksiyonu


Aşağıda, MyService sınıfı bir service olarak işaretlenmiş ve MyController sınıfında bu service otomatik olarak enjekte edilmiştir.


1. MyService (Servis Sınıfı):


import org.springframework.stereotype.Service;


@Service

public class MyService {


    public String serviceMethod() {

        return "Service running";

    }

}



  • @Service anotasyonu, bu sınıfın bir Spring bileşeni olduğunu ve Spring IoC konteynerı tarafından yönetileceğini belirtir.
  • serviceMethod() isimli bir metot, basit bir işlem yapar ve "Service running" mesajını döner.


2. MyController (Controller Sınıfı):


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

@RequestMapping("/api")

public class MyController {


    private final MyService myService;


    @Autowired  // Bağımlılığın enjekte edilmesini sağlar

    public MyController(MyService myService) {

        this.myService = myService;

    }


    @GetMapping("/runService")

    public String runService() {

        return myService.serviceMethod();

    }

}



Açıklamalar:

  1. @Autowired: Bu anotasyon ile Spring, MyService sınıfını otomatik olarak MyController sınıfına enjekte eder. Bu sayede MyController, MyService'e bağımlı olur, ancak manuel olarak oluşturmak yerine Spring tarafından yönetilir.
  2. Bağımlılık Enjeksiyonu: MyController sınıfı, MyService sınıfına bağımlıdır, ancak bu bağımlılığı Spring yönetir ve gerekli olduğunda MyService bean'ini oluşturup MyController'a enjekte eder.
  3. Constructor Injection: En yaygın bağımlılık enjeksiyonu yöntemlerinden biri constructor enjeksiyonudur. Bu yöntem, bağımlılıkları sınıfın constructor'ında alır ve test edilebilirliği artırır. Field Injection yerine constructor enjeksiyonunu tercih etmek daha güvenlidir.


Dependency Injection Çalışma Şekli:

  • Inversion of Control (IoC): Spring, bağımlılıkları otomatik olarak yönetir ve kontrol eder. Yani, sınıflarınızın bağımlılıklarını manuel olarak oluşturmanız gerekmez; Spring bunu sizin için yapar. Bu, kontrolün tersine çevrilmesi (Inversion of Control) anlamına gelir.


Kullanım:

  • Uygulamanızı başlattıktan sonra /api/runService adresine GET isteği gönderdiğinizde, MyController sınıfı aracılığıyla MyService sınıfının serviceMethod() metodunu çağırır ve "Service running" mesajını döner.


Diğer Yöntemler:

  • Setter Injection: Bağımlılıkları setter metotları aracılığıyla enjekte etmek.
  • Field Injection: Alan seviyesinde (değişken seviyesinde) enjeksiyon. Bu yöntem yaygın olsa da, test edilebilirlik ve esneklik açısından constructor enjeksiyon tercih edilmelidir.


Özet:

  • Bağımlılık Enjeksiyonu: Bir sınıfın başka bir sınıfa olan bağımlılığı Spring IoC konteyneri tarafından yönetilir.
  • @Autowired: Spring, ilgili bağımlılıkları otomatik olarak enjekte eder.
  • @Service, @Repository, @Component: Bu anotasyonlar sınıfların Spring tarafından yönetilen bean'ler olduğunu belirtir.


Bu yapı, Spring Boot uygulamalarında bağımlılıkların yönetilmesini otomatik hale getirir ve kodunuzu daha modüler, esnek ve test edilebilir yapar.


8. Spring Boot DevTools Kullanımı

  • 8. Spring Boot DevTools Kullanımı


Spring Boot DevTools, geliştirme sürecinde geliştirmeleri hızlandırmak için kullanılır. En önemli özelliği, kodda yapılan değişiklikleri algılayarak uygulamanızı otomatik olarak yeniden başlatmasıdır. Bu, her kod değişikliğinden sonra uygulamayı manuel olarak yeniden başlatmak zorunda kalmadan hızlı bir geliştirme döngüsü sağlar.


DevTools’un Başlıca Özellikleri:

  1. Otomatik Yeniden Başlatma (Automatic Restart): Kod değişikliklerini algılayarak uygulamanın yeniden başlatılmasını sağlar.
  2. LiveReload: Tarayıcıda sayfanın otomatik olarak yenilenmesini sağlar (LiveReload eklentisiyle).
  3. Hızlı Uygulama Başlatma: Geliştirme modunda uygulama daha hızlı başlatılır.
  4. Özel Geliştirme ve Üretim Yapılandırması: application.properties içinde geliştirme ve üretim yapılandırmalarını ayırt edebilir.
  5. Önbellek Devre Dışı Bırakma: Thymeleaf gibi şablonlar için önbellekleme işlemlerini geliştirirken devre dışı bırakır.


Spring Boot DevTools Bağımlılığını Ekleme


Maven kullanıyorsanız, DevTools bağımlılığını pom.xml dosyanıza şu şekilde ekleyebilirsiniz:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-devtools</artifactId>

    <optional>true</optional>

</dependency>



Gradle kullanıyorsanız, build.gradle dosyasına şu satırı ekleyebilirsiniz:



implementation 'org.springframework.boot:spring-boot-devtools'



Önemli Not:

  • DevTools bağımlılığı yalnızca geliştirme ortamında çalışır. Üretim ortamında otomatik olarak devre dışı bırakılır.
  • Bu bağımlılık, uygulamanın .jar dosyası üretildiğinde veya dağıtıldığında dahil edilmez. Yani üretim ortamında performansı etkilemez.


Otomatik Yeniden Başlatma Özelliği:

Spring Boot DevTools'un sağladığı automatic restart özelliği, sadece sınıf dosyalarında (Java, Kotlin vb.) yapılan değişikliklerde uygulamayı yeniden başlatır. Yeniden başlatma işlemi, eski uygulama verilerini korur, bu yüzden hızlı ve etkili bir yöntemdir. Örneğin:


  • Eğer Controller, Service, Repository veya başka bir sınıfta değişiklik yaparsanız, uygulama bu değişiklikleri otomatik olarak algılar ve uygulamanızı yeniden başlatır.


LiveReload Kullanımı:

LiveReload, tarayıcıdaki sayfanın otomatik olarak yenilenmesini sağlayan bir özelliktir. LiveReload eklentisini tarayıcınıza kurarak, uygulamada yapılan HTML, CSS veya JavaScript gibi değişiklikleri otomatik olarak görebilirsiniz. Tarayıcıda sayfayı manuel olarak yenilemek zorunda kalmadan güncellemeleri anında görebilirsiniz.


application.properties Ayarları:


application.properties dosyanıza ekleyebileceğiniz bazı DevTools ayarları:



# DevTools otomatik yeniden başlatmayı etkinleştirir (varsayılan olarak true)

spring.devtools.restart.enabled=true


# LiveReload etkinleştirir

spring.devtools.livereload.enabled=true


# Şablon motorları (Thymeleaf gibi) için önbellekleme devre dışı bırakılır

spring.thymeleaf.cache=false



DevTools ile Geliştirme Sürecini Hızlandırma:

  • Uygulama geliştirirken Spring Boot DevTools’u kullanarak kodda yaptığınız değişikliklerin anında devreye girmesini sağlayabilirsiniz.
  • Thymeleaf, CSS veya JavaScript gibi statik dosyalarda yapılan değişiklikleri görmek için sayfayı manuel olarak yenilemeden tarayıcıda anında görebilirsiniz.


Özet:

  • Spring Boot DevTools, geliştirme sürecini hızlandıran bir bağımlılıktır.
  • Otomatik yeniden başlatma, LiveReload gibi özelliklerle kodda yapılan değişikliklerin anında uygulamada görünmesini sağlar.
  • Üretim ortamında devre dışıdır, sadece geliştirme sürecinde kullanılır.


Spring Boot DevTools, Spring Boot uygulamalarınızı geliştirirken size daha hızlı bir geliştirme döngüsü sağlar ve verimliliğinizi artırır.

  


### 9. **Model (Entity) Sınıfı Oluşturma**

- JPA ile bir **Entity** sınıfı oluşturun:

  ```java

  @Entity

  public class Product {

      @Id

      @GeneratedValue(strategy = GenerationType.IDENTITY)

      private Long id;

      private String name;

      private double price;

      // Getters, Setters

  }

  


10. JPA Repository Kullanımı

  • CrudRepository ya da JpaRepository kullanarak veri tabanı işlemleri yapın:

  •   public interface ProductRepository extends JpaRepository<Product, Long> {
  •   }

10. JPA Repository Kullanımı


Spring Data JPA, veri tabanı işlemlerini kolayca yönetmek için JpaRepository, CrudRepository gibi hazır arayüzler sunar. Bu arayüzler, veri tabanı üzerinde CRUD (Create, Read, Update, Delete) işlemleri yapmayı büyük ölçüde basitleştirir ve bu işlemleri gerçekleştirirken neredeyse hiç SQL kodu yazmanıza gerek kalmaz.


CrudRepository ve JpaRepository Farkı:

  • CrudRepository: Tüm temel CRUD (Create, Read, Update, Delete) işlemleri için metotlar içerir. Daha temel bir arayüzdür.
  • JpaRepository: CrudRepository'nin tüm özelliklerini içerir ve ayrıca daha gelişmiş özellikler (pagination, sorting vb.) sağlar. Genellikle daha fazla fonksiyon içerdiği için tercih edilir.


Örnek Senaryo: JpaRepository Kullanarak Veri Tabanı İşlemleri Yapma


Aşağıda, bir Product varlığı (entity) için CRUD işlemlerini gerçekleştiren basit bir ProductRepository örneği göreceksiniz.


1. Product Entity Sınıfı

  • İlk olarak, veri tabanında saklanacak olan varlığı (entity) oluşturmalısınız.



import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;


@Entity

public class Product {


    @Id

    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;


    private String name;

    private double price;


    // Getters and Setters


    public Long getId() {

        return id;

    }


    public void setId(Long id) {

        this.id = id;

    }


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public double getPrice() {

        return price;

    }


    public void setPrice(double price) {

        this.price = price;

    }

}



  • @Entity: Bu anotasyon, bu sınıfın bir veri tabanı tablosuna eşleneceğini belirtir.
  • @Id ve @GeneratedValue: id alanı bu tablodaki her kaydın benzersiz anahtarıdır ve veri tabanında otomatik olarak oluşturulur.


2. JpaRepository Arayüzü ile CRUD İşlemleri


ProductRepository sınıfı, JpaRepository'yi genişleterek temel CRUD işlemlerini gerçekleştirebilir.



import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.stereotype.Repository;


@Repository

public interface ProductRepository extends JpaRepository<Product, Long> {

}



  • JpaRepository<Product, Long>: Product sınıfı üzerinde CRUD işlemleri gerçekleştiren bir arayüzdür. Burada Product entity'si ve entity'nin ID tipi Long olarak tanımlanmıştır.
  • @Repository: Bu anotasyon, Spring'e bu sınıfın bir veri erişim bileşeni olduğunu belirtir. Ancak Spring Data JPA, @Repository anotasyonu olmadan da repository'yi otomatik olarak algılar.


3. Service Katmanı


Repository'yi kullanarak iş mantığını yönetmek için bir Service sınıfı oluşturabilirsiniz.



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import java.util.List;


@Service

public class ProductService {


    private final ProductRepository productRepository;


    @Autowired

    public ProductService(ProductRepository productRepository) {

        this.productRepository = productRepository;

    }


    public List<Product> getAllProducts() {

        return productRepository.findAll();

    }


    public Product saveProduct(Product product) {

        return productRepository.save(product);

    }


    public Product getProductById(Long id) {

        return productRepository.findById(id).orElse(null);

    }


    public void deleteProduct(Long id) {

        productRepository.deleteById(id);

    }

}



  • findAll(): Tüm Product kayıtlarını getirir.
  • save(): Yeni bir Product kaydeder veya mevcut olanı günceller.
  • findById(): ID ile bir Product getirir.
  • deleteById(): ID ile bir Product siler.


4. Controller Katmanı


Son olarak, HTTP isteklerini işlemek için bir Controller sınıfı oluşturabilirsiniz.



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;


import java.util.List;


@RestController

@RequestMapping("/api/products")

public class ProductController {


    private final ProductService productService;


    @Autowired

    public ProductController(ProductService productService) {

        this.productService = productService;

    }


    @GetMapping

    public List<Product> getAllProducts() {

        return productService.getAllProducts();

    }


    @PostMapping

    public Product createProduct(@RequestBody Product product) {

        return productService.saveProduct(product);

    }


    @GetMapping("/{id}")

    public Product getProductById(@PathVariable Long id) {

        return productService.getProductById(id);

    }


    @DeleteMapping("/{id}")

    public void deleteProduct(@PathVariable Long id) {

        productService.deleteProduct(id);

    }

}



  • @GetMapping: Tüm ürünleri getirir (GET /api/products).
  • @PostMapping: Yeni bir ürün oluşturur (POST /api/products).
  • @GetMapping("/{id}"): ID'ye göre bir ürünü getirir (GET /api/products/{id}).
  • @DeleteMapping("/{id}"): ID'ye göre bir ürünü siler (DELETE /api/products/{id}).


5. Veri Tabanı Yapılandırması (H2)


application.properties dosyanıza H2 veri tabanı yapılandırmasını ekleyin:



spring.datasource.url=jdbc:h2:mem:testdb

spring.datasource.driverClassName=org.h2.Driver

spring.datasource.username=sa

spring.datasource.password=

spring.jpa.hibernate.ddl-auto=update

spring.h2.console.enabled=true



Uygulamanın Çalıştırılması:


  • Uygulamanızı başlattıktan sonra http://localhost:8080/api/products adresine GET isteği göndererek tüm ürünleri listeleyebilir ya da Postman gibi bir araçla POST isteği yaparak yeni bir ürün oluşturabilirsiniz.


Özet:

  • JpaRepository ve CrudRepository, veri tabanı işlemlerini kolaylaştırır ve CRUD operasyonları için ihtiyacınız olan tüm temel metotları sağlar.
  • Spring Data JPA, repository'leri otomatik olarak yönetir ve bu repository'leri kullanarak veri tabanı işlemlerini basit bir şekilde gerçekleştirebilirsiniz.


11. Veri Tabanı Yapılandırması

  • H2 ya da MySQL gibi bir veri tabanı yapılandırın.

11. Veri Tabanı Yapılandırması


Spring Boot uygulamalarında veri tabanı yapılandırması oldukça basittir. Spring Boot, H2 gibi yerleşik veri tabanlarını kullanarak hızlı geliştirme yapmanızı sağlarken, MySQL gibi daha büyük veri tabanlarıyla da entegrasyon sağlar.


Aşağıda hem H2 hem de MySQL veri tabanlarının nasıl yapılandırılacağını açıklıyorum:


1. H2 Veri Tabanı Yapılandırması


H2, Spring Boot uygulamalarında yerleşik olarak kullanılan hafif, bellek içi bir veri tabanıdır. Geliştirme ve test işlemleri için oldukça kullanışlıdır. Hafif olduğu için hızlıca kurulum yaparak kullanabilirsiniz.


H2 Bağımlılığı (pom.xml):



<dependency>

    <groupId>com.h2database</groupId>

    <artifactId>h2</artifactId>

    <scope>runtime</scope>

</dependency>



application.properties ile H2 Yapılandırması:



# H2 veri tabanı yapılandırması

spring.datasource.url=jdbc:h2:mem:testdb

spring.datasource.driverClassName=org.h2.Driver

spring.datasource.username=sa

spring.datasource.password=

spring.h2.console.enabled=true

spring.h2.console.path=/h2-console


# Hibernate yapılandırması (JPA)

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true



  • spring.datasource.url=jdbc:h2:mem:testdb: H2 için bellek içi bir veri tabanı kullanılır. Her uygulama başlatıldığında temiz bir veri tabanı ile başlar.
  • spring.h2.console.enabled=true: H2 için bir web konsolu sağlar. Bu konsolu kullanarak veri tabanını tarayıcı üzerinden yönetebilirsiniz.
  • spring.h2.console.path=/h2-console: H2 konsoluna /h2-console yolundan erişebilirsiniz.
  • spring.jpa.hibernate.ddl-auto=update: Bu ayar, JPA'nın veri tabanı tablolarını otomatik olarak oluşturup güncellemesine olanak tanır.


H2 Konsoluna Erişim:


  • Uygulamanız çalışırken, tarayıcınızda http://localhost:8080/h2-console adresine gidin.
  • Veri tabanı URL’si olarak jdbc:h2:mem:testdb'yi kullanarak konsola giriş yapabilirsiniz.


Özet:

  • H2, geliştirme ve test için hızlıca kurulabilen hafif bir veri tabanıdır.
  • Konsol arayüzü ile veri tabanını yönetmek oldukça kolaydır.


————————


2. MySQL Veri Tabanı Yapılandırması


MySQL, yaygın olarak kullanılan, güçlü ve yüksek performanslı bir veri tabanıdır. Spring Boot ile MySQL kullanarak kalıcı verilerle çalışabilirsiniz.


MySQL Bağımlılığı (pom.xml):



<dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <scope>runtime</scope>

</dependency>



application.properties ile MySQL Yapılandırması:



# MySQL veri tabanı yapılandırması

spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC

spring.datasource.username=root

spring.datasource.password=your_password

spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver


# Hibernate yapılandırması (JPA)

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect



  • spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name: MySQL sunucusuna bağlanmak için URL yapısı. your_database_name kısmını kendi veri tabanı isminizle değiştirmelisiniz.
  • spring.datasource.username=root ve spring.datasource.password=your_password: MySQL sunucusundaki kullanıcı adı ve şifreniz.
  • spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver: MySQL JDBC sürücüsü.
  • spring.jpa.hibernate.ddl-auto=update: JPA'nın veri tabanı şemasını otomatik güncellemesini sağlar. İlk çalıştırmada tabloları otomatik olarak oluşturur.
  • spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect: MySQL veri tabanı ile uyumlu bir Hibernate dilini belirtir.


MySQL Veri Tabanı Oluşturma:


MySQL'de uygulamanızın kullanacağı veri tabanını manuel olarak oluşturmanız gerekebilir:



CREATE DATABASE your_database_name;



Ardından, Spring Boot uygulamanız yukarıda belirttiğiniz veri tabanına bağlanır ve tabloları otomatik olarak oluşturur.


MySQL ile Bağlantı Problemleri:


  • Eğer MySQL'e bağlanırken sorun yaşıyorsanız, aşağıdaki adımları kontrol edin:
    • MySQL servisinin çalışır durumda olduğundan emin olun.
    • MySQL'de doğru portu (varsayılan 3306) kullandığınızdan emin olun.
    • MySQL sürümünüze uygun Dialect ayarını kontrol edin.


Özet:

  • MySQL, büyük ve kalıcı verilerle çalışmak için ideal bir veri tabanıdır.
  • Spring Boot, MySQL ile kolayca entegre olabilir ve veri tabanı işlemlerini sorunsuz bir şekilde gerçekleştirebilir.


————————


Hangi Veri Tabanı Ne Zaman Kullanılmalı?

  • H2: Geliştirme ve test süreçlerinde, hızlı kurulum ve hafifliği nedeniyle tercih edilir.
  • MySQL: Üretim ortamlarında ve kalıcı veri saklama ihtiyacınız varsa tercih edilmelidir.


Her iki veri tabanı da Spring Boot ile kolayca yapılandırılabilir. Seçiminizi projenizin ihtiyaçlarına göre yapabilirsiniz.

12. Spring Boot Actuator

12. Spring Boot Actuator


Spring Boot Actuator, Spring Boot uygulamalarını izlemek, yönetmek ve sağlık durumu, uygulama metrikleri gibi bilgileri kontrol etmek için kullanılan bir modüldür. Actuator, uygulamanızın iç işleyişini gözlemlemenize yardımcı olur ve üretim ortamlarında uygulamanızı daha güvenli bir şekilde izleyebilmeniz için çeşitli uç noktalar (endpoints) sağlar.


Actuator ile sağlık kontrolü (health checks), metrikler, bean bilgileri, çevresel yapılandırmalar gibi birçok bilgiyi dinamik olarak alabilirsiniz.


Spring Boot Actuator Bağımlılığını Ekleme


Maven kullanıyorsanız, Actuator bağımlılığını pom.xml dosyanıza şu şekilde ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>



Gradle kullanıyorsanız, build.gradle dosyasına şu satırı ekleyin:



implementation 'org.springframework.boot:spring-boot-starter-actuator'



Actuator Özelliklerini Etkinleştirme


Varsayılan olarak, sadece belirli Actuator uç noktaları etkinleştirilmiştir (örneğin, /health ve /info). Daha fazla uç noktayı etkinleştirmek veya yapılandırmak için application.properties dosyasına ayarlar ekleyebilirsiniz.


application.properties ile Actuator Yapılandırması:



# Actuator URL yolunu değiştirme (varsayılan olarak /actuator kullanılır)

management.endpoints.web.base-path=/actuator


# Tüm actuator uç noktalarını etkinleştirir

management.endpoints.web.exposure.include=*


# Sağlık kontrolü detaylarını gösterir

management.endpoint.health.show-details=always



  • management.endpoints.web.base-path=/actuator: Actuator uç noktalarının temel yolunu belirtir (varsayılan olarak /actuator yolunu kullanır).
  • management.endpoints.web.exposure.include=*: Bu ayar, tüm actuator uç noktalarını (endpoints) etkinleştirir. Belirli uç noktaları etkinleştirmek için sadece istediğiniz uç noktaları virgülle ayırarak ekleyebilirsiniz (örneğin, health,info).
  • management.endpoint.health.show-details=always: Sağlık kontrolü (health check) detaylarını her zaman gösterir. Bu, özellikle uygulamanın durumunu (örneğin, veri tabanı bağlantıları) kontrol etmek için faydalıdır.


Actuator Uç Noktalarını Kullanma


Spring Boot Actuator, uygulamanız hakkında bilgi edinmek için bir dizi hazır uç nokta sunar. Uygulamanızı başlattıktan sonra tarayıcıda veya Postman gibi bir araçla bu uç noktaları kullanabilirsiniz.


Yaygın Actuator Uç Noktaları:

  • /actuator/health: Uygulamanızın sağlık durumunu kontrol eder. Bu uç nokta, veri tabanı, disk durumu, dış servisler gibi bağımlılıkların sağlıklı olup olmadığını bildirir.
    • http://localhost:8080/actuator/health


Örnek Yanıt:


   {

       "status": "UP"

   }



  • /actuator/info: Uygulamanız hakkında bilgi döner. application.properties dosyasında belirttiğiniz özel bilgilerle yapılandırılabilir.
    • http://localhost:8080/actuator/info


  • /actuator/metrics: Uygulamanızın performans metriklerini döner (CPU kullanımı, bellek kullanımı gibi).
    • http://localhost:8080/actuator/metrics


  • /actuator/env: Uygulamanızın ortam değişkenlerini ve yapılandırma bilgilerini gösterir.
    • http://localhost:8080/actuator/env


  • /actuator/beans: Spring IoC konteynerındaki bean'lerin listesini döner.
    • http://localhost:8080/actuator/beans


  • /actuator/loggers: Uygulamadaki log seviyelerini kontrol eder ve değiştirme imkanı sunar.
    • http://localhost:8080/actuator/loggers


  • /actuator/threaddump: Uygulamanın mevcut thread dump’ını gösterir. Bu, uygulamanın performansını izlemek için faydalıdır.
    • http://localhost:8080/actuator/threaddump


Özelleştirilmiş Bilgi (info) Uç Noktası


/actuator/info uç noktası aracılığıyla uygulama hakkında özel bilgiler döndürebilirsiniz. Bunun için application.properties dosyasına özel bilgiler ekleyebilirsiniz:



info.app.name=My Spring Boot Application

info.app.description=This is a sample Spring Boot application using Actuator

info.app.version=1.0.0



/actuator/info uç noktasına istek yaptığınızda, şu şekilde bir yanıt alırsınız:



{

    "app": {

        "name": "My Spring Boot Application",

        "description": "This is a sample Spring Boot application using Actuator",

        "version": "1.0.0"

    }

}



Sağlık Kontrolleri (Health Checks) ve Metrikler


Spring Boot Actuator, uygulamanızın sağlık durumu ile ilgili birçok metriği otomatik olarak toplar. Örneğin, /actuator/health uç noktasından veri tabanı bağlantısı, mesajlaşma kuyruğu, disk alanı gibi önemli servislerin durumu hakkında bilgi alabilirsiniz.


Eğer uygulamanızda bir veri tabanı bağlıysa, /actuator/health uç noktası veri tabanı durumunu da gösterecektir. Örneğin, H2 ya da MySQL veri tabanı bağlıysa şu şekilde bir yanıt alabilirsiniz:



{

    "status": "UP",

    "components": {

        "db": {

            "status": "UP",

            "details": {

                "database": "H2",

                "result": 1

            }

        },

        "diskSpace": {

            "status": "UP",

            "details": {

                "total": 499963174912,

                "free": 320593854464,

                "threshold": 10485760

            }

        }

    }

}



Özet:

  • Spring Boot Actuator, uygulamanızın sağlık durumunu ve performans metriklerini izlemek için kullanışlı uç noktalar sağlar.
  • Actuator, üretim ortamında izleme, hata teşhisi ve performans ölçümü gibi görevlerde önemli bir araçtır.
  • Uç noktalar, uygulamanız hakkında derinlemesine bilgi verir ve gerektiğinde özelleştirilebilir.
  • Özellikle /health ve /metrics uç noktaları, üretim ortamlarında uygulamanızın sağlığını ve performansını izlemek için hayati öneme sahiptir.


Actuator, uygulamanızın sağlıklı çalıştığından emin olmak ve performansını izlemek için güçlü bir çözümdür.

13. Error Handling (Hata Yönetimi)

13. Error Handling (Hata Yönetimi)


Spring Boot uygulamalarında, hata yönetimi önemli bir konudur. Hataları düzgün bir şekilde yakalamak ve kullanıcıya anlamlı hata mesajları döndürmek, uygulamanın güvenilirliğini artırır. Spring, hata yönetimi için @ExceptionHandler anotasyonu ve @ControllerAdvice gibi araçlar sağlar. Bu araçlar, özel durumları (exception) yakalayarak onlara uygun yanıtlar döndürebilmenize olanak tanır.


@ExceptionHandler ile Özel Hata Yönetimi


@ExceptionHandler anotasyonu, bir controller veya global olarak belirli hataları yakalayıp yönetmek için kullanılır. Örneğin, bir kaynak bulunamadığında (404 hatası) özel bir yanıt döndürmek isteyebilirsiniz. Bunun için @ExceptionHandler anotasyonu kullanılır.


Örnek: Kaynak Bulunamadığında Hata Yönetimi


Bir kaynak (örneğin, bir ürün) bulunamadığında, ResourceNotFoundException fırlatabilir ve bu hatayı özel bir şekilde ele alabilirsiniz.


1. Özel İstisna (Exception) Sınıfı


İlk olarak, bir özel hata sınıfı oluşturun:



public class ResourceNotFoundException extends RuntimeException {


    public ResourceNotFoundException(String message) {

        super(message);

    }

}



Bu sınıf, RuntimeException sınıfını genişletir ve ResourceNotFoundException hatasını fırlatmak için kullanılır.


2. Controller'da @ExceptionHandler ile Hata Yakalama


Controller sınıfınızda, @ExceptionHandler kullanarak bu özel durumu yakalayabilirsiniz.



import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

@RequestMapping("/api/products")

public class ProductController {


    // Ürünleri tutan basit bir liste (örnek amaçlı)

    private Map<Long, String> products = new HashMap<>();


    @GetMapping("/{id}")

    public ResponseEntity<String> getProductById(@PathVariable Long id) {

        String product = products.get(id);


        if (product == null) {

            throw new ResourceNotFoundException("Product not found with id: " + id);

        }


        return ResponseEntity.ok(product);

    }


    // Özel hata yakalayıcı

    @ExceptionHandler(ResourceNotFoundException.class)

    public ResponseEntity<?> resourceNotFoundHandler(ResourceNotFoundException ex) {

        return ResponseEntity.notFound().build();

    }

}



Açıklamalar:

  1. @ExceptionHandler: Bu anotasyon, ResourceNotFoundException fırlatıldığında yakalanmasını ve uygun bir yanıt döndürülmesini sağlar.
  2. ResponseEntity.notFound().build(): 404 Not Found HTTP yanıtını döner.
  3. throw new ResourceNotFoundException("Product not found with id: " + id): İlgili ürün bulunamazsa bu özel hatayı fırlatır.


Bu yapı sayesinde, ürün bulunmadığında kullanıcıya 404 Not Found yanıtı gönderilecektir.


3. Global Exception Handling (Global Hata Yönetimi) - @ControllerAdvice


Eğer uygulamanızdaki tüm controller'lar için global bir hata yönetimi oluşturmak istiyorsanız, @ControllerAdvice anotasyonunu kullanabilirsiniz. Bu anotasyon, uygulamanın her yerinde meydana gelen hataları yakalar ve uygun yanıtlar döndürebilir.


Global Hata Yönetimi Örneği:



import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.context.request.WebRequest;


@ControllerAdvice

public class GlobalExceptionHandler {


    @ExceptionHandler(ResourceNotFoundException.class)

    public ResponseEntity<?> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Error: " + ex.getMessage());

    }


    // Diğer istisnalar için genel bir yakalayıcı

    @ExceptionHandler(Exception.class)

    public ResponseEntity<?> handleGlobalException(Exception ex, WebRequest request) {

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred: " + ex.getMessage());

    }

}



Açıklamalar:

  1. @ControllerAdvice: Bu anotasyon, global hata yönetimi sağlar. Tüm controller'larda meydana gelen hatalar burada yakalanır.
  2. @ExceptionHandler(ResourceNotFoundException.class): ResourceNotFoundException özel hatasını yakalar ve kullanıcıya anlamlı bir hata mesajı ile yanıt verir.
  3. @ExceptionHandler(Exception.class): Genel olarak yakalanmayan tüm istisnalar için global bir hata yönetimidir ve 500 Internal Server Error yanıtı döner.


4. Hata Yanıtları için Detaylı Bilgi


Kullanıcılara daha detaylı hata mesajları döndürmek için özel bir hata yanıtı sınıfı oluşturabilirsiniz.


Özel Hata Yanıtı Sınıfı:



public class ErrorResponse {

    private String message;

    private String details;


    public ErrorResponse(String message, String details) {

        this.message = message;

        this.details = details;

    }


    // Getters and Setters

}



Hata Yanıtını Kullanma:



@ExceptionHandler(ResourceNotFoundException.class)

public ResponseEntity<ErrorResponse> resourceNotFoundHandler(ResourceNotFoundException ex, WebRequest request) {

    ErrorResponse errorResponse = new ErrorResponse(ex.getMessage(), request.getDescription(false));

    return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);

}



Bu örnekte, kullanıcıya daha ayrıntılı bir hata yanıtı gönderilir. Yanıt şu şekilde görünebilir:



{

    "message": "Product not found with id: 1",

    "details": "uri=/api/products/1"

}



Özet:

  • @ExceptionHandler, belirli bir istisna (exception) meydana geldiğinde özel hata yanıtları oluşturmak için kullanılır.
  • @ControllerAdvice ile global hata yönetimi sağlayabilir ve uygulamanızın genelinde meydana gelen hataları tek bir yerde yönetebilirsiniz.
  • Kullanıcılara anlamlı hata mesajları dönmek, uygulamanızın kullanıcı dostu olmasını sağlar ve hata yönetimi yapısını basitleştirir.


Spring Boot uygulamalarında hata yönetimi, ExceptionHandler ve ControllerAdvice gibi araçlarla oldukça esnek ve güçlü hale gelir.

14. Logging Kullanımı

14. Logging Kullanımı


Loglama, bir uygulamanın çalışma durumunu izlemek, hataları tespit etmek ve performans verilerini kaydetmek için önemli bir tekniktir. Spring Boot, varsayılan olarak SLF4J (Simple Logging Facade for Java) ve Logback kütüphanelerini kullanır. SLF4J, uygulamanızda kullanılacak loglama framework'ü için bir ara yüz sağlar, Logback ise varsayılan loglama framework'ü olarak gelir.


1. SLF4J ve Logback Kütüphaneleri ile Loglama


Spring Boot projelerinde loglama işlemi için ekstra bir bağımlılık eklemenize gerek yoktur. SLF4J ve Logback Spring Boot projeleri için varsayılan olarak entegre edilmiştir. Yani doğrudan loglama işlemlerine başlayabilirsiniz.


2. Loglama için Gerekli Kod:

Aşağıdaki örnekte, SLF4J ile bir log nesnesi oluşturuyoruz ve uygulamada loglama işlemlerini gerçekleştiriyoruz.



import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Service;


@Service

public class MyService {


    private static final Logger logger = LoggerFactory.getLogger(MyService.class);


    public void performService() {

        logger.info("Service is running");


        try {

            // Örnek iş mantığı

            int result = 10 / 2;

            logger.debug("Calculation result: {}", result);

        } catch (Exception e) {

            logger.error("An error occurred: {}", e.getMessage());

        }

    }

}



Açıklamalar:

  1. LoggerFactory.getLogger(MyService.class): Bu satır, MyService sınıfı için bir Logger örneği oluşturur. Bu örnek, uygulamanın her yerinde loglama işlemlerini yönetir.
  2. logger.info(): Bilgilendirme seviyesinde (INFO) bir mesaj loglar. Genellikle, uygulamanın önemli adımlarını kaydetmek için kullanılır.
  3. logger.debug(): Debug seviyesinde bir mesaj loglar. Genellikle, geliştirme sürecinde veya hata ayıklama (debugging) sırasında kullanılır.
  4. logger.error(): Hata (ERROR) seviyesinde bir mesaj loglar. Genellikle, uygulamada meydana gelen hataları kaydetmek için kullanılır.


Log Seviyeleri:

  • TRACE: En ayrıntılı log seviyesidir. Çok fazla ayrıntı içerir ve nadiren kullanılır.
  • DEBUG: Geliştirici odaklı bilgileri içerir. Geliştirme ve hata ayıklama sırasında kullanılır.
  • INFO: Genel bilgi mesajlarıdır. Uygulamanın işleyişini izlemek için kullanılır.
  • WARN: Uyarı mesajlarıdır. Bir sorun olasılığı hakkında bilgi verir, ancak uygulama çalışmaya devam eder.
  • ERROR: Hatalı durumlar hakkında bilgi verir. Genellikle istisnalar veya kritik hatalar için kullanılır.


2. Logback Yapılandırması


Logback, Spring Boot'un varsayılan loglama framework'üdür. Logback’i yapılandırmak için logback-spring.xml veya logback.xml dosyasını kullanabilirsiniz. Örneğin, loglama çıktısının formatını, seviyesini ve yönlendirilmesini yapılandırabilirsiniz.


logback-spring.xml Dosyası Örneği:



<configuration>


    <!-- Console appender - logları konsola yazdırır -->

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

        <encoder>

            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>

        </encoder>

    </appender>


    <!-- File appender - logları bir dosyaya yazdırır -->

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <file>app-log.log</file>

        <encoder>

            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>

        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

            <!-- Her gün yeni bir log dosyası oluşturur -->

            <fileNamePattern>app-log-%d{yyyy-MM-dd}.log</fileNamePattern>

            <maxHistory>7</maxHistory> <!-- En fazla 7 günlük log dosyası saklar -->

        </rollingPolicy>

    </appender>


    <!-- Log seviyeleri ayarı -->

    <root level="info">

        <appender-ref ref="STDOUT" />

        <appender-ref ref="FILE" />

    </root>


</configuration>



Açıklamalar:

  1. <appender name="STDOUT">: Konsola log mesajlarını yazdırır. Log mesajları System.out akışına yönlendirilir.
  2. <appender name="FILE">: Log mesajlarını bir dosyaya yazar. Burada günlük log dosyası tutulur ve her gün yeni bir dosya oluşturulur (app-log-2024-10-30.log gibi).
  3. <root level="info">: Loglama seviyesini belirtir. Bu örnekte, INFO seviyesindeki ve daha yüksek (WARN, ERROR) log mesajları işlenecektir.
  4. <pattern>: Log mesajlarının formatını tanımlar. Burada tarih, log seviyesi, logger adı ve mesajın kendisi yer alır.


3. Log Seviyelerini application.properties Dosyasında Belirleme


Log seviyelerini application.properties dosyasında da yapılandırabilirsiniz:



# Genel log seviyesi

logging.level.root=INFO


# Belirli paketler için log seviyeleri

logging.level.org.springframework.web=DEBUG

logging.level.com.example=DEBUG


# Konsol ve dosya için log formatı

logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n

logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n


# Dosya loglama ayarları

logging.file.name=app-log.log

logging.file.max-history=7



  • logging.level.root: Tüm uygulama için genel log seviyesini ayarlar.
  • logging.level.org.springframework.web=DEBUG: Belirli bir paket veya sınıf için log seviyesini belirler. Bu örnekte, org.springframework.web paketindeki loglar DEBUG seviyesinde olacaktır.
  • logging.pattern.console ve logging.pattern.file: Logların konsol ve dosyadaki formatını belirler.
  • logging.file.name=app-log.log: Log dosyasının adını belirtir.
  • logging.file.max-history=7: Maksimum 7 günlük log dosyasını saklar.


4. Log Mesajlarını Dosyaya Yönlendirme

Yukarıda gösterilen logback-spring.xml veya application.properties yapılandırmalarını kullanarak log mesajlarını dosyaya yazabilirsiniz. Böylece loglar uygulamanın yaşam döngüsü boyunca kaydedilir ve geçmiş loglar incelenebilir.


Özet:

  • SLF4J ile loglama işlemlerini yönetir ve Logback varsayılan loglama framework'ü olarak gelir.
  • Logback kullanarak logların hangi formatta ve nereye (konsol, dosya) yazılacağını özelleştirebilirsiniz.
  • Log seviyelerini ve yapılandırmalarını application.properties ya da logback-spring.xml dosyaları üzerinden yönetebilirsiniz.
  • Geliştirme, test ve üretim ortamlarında farklı loglama ayarları yaparak uygulamanızı daha izlenebilir hale getirebilirsiniz.


Loglama, uygulamanızın sağlıklı çalışmasını izlemek, performansı değerlendirmek ve hataları hızlı bir şekilde bulmak için önemli bir araçtır.

15. Spring Boot Test

15. Spring Boot Test


Spring Boot, JUnit ve Mockito kütüphanelerini entegre ederek birim testleri (unit tests) ve entegrasyon testlerini kolayca yazmanızı sağlar. JUnit birim testleri yazmak için en yaygın kullanılan test kütüphanelerinden biridir ve Mockito ise bağımlılıkların (dependencies) sahte nesneler (mock objects) ile taklit edilmesine olanak tanır. Birlikte, Spring Boot uygulamalarının tüm katmanlarını test etmek için güçlü bir kombinasyon sağlarlar.


1. JUnit ve Mockito Bağımlılıklarını Eklemek


Eğer JUnit ve Mockito bağımlılıkları Spring Boot projenizde yoksa, bu bağımlılıkları pom.xml dosyanıza ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-test</artifactId>

    <scope>test</scope>

</dependency>

<dependency>

    <groupId>org.mockito</groupId>

    <artifactId>mockito-core</artifactId>

    <scope>test</scope>

</dependency>



spring-boot-starter-test bağımlılığı, JUnit, Mockito, ve diğer test kütüphanelerini içerir.


2. Temel Spring Boot Test Sınıfı


Bir Spring Boot test sınıfı genellikle @SpringBootTest anotasyonu ile işaretlenir ve Spring Boot'un tüm yapılandırmasını yükler. Bu, entegrasyon testleri için kullanılır. JUnit ile testleri çalıştırmak için her test metodu @Test anotasyonu ile işaretlenir.


Örnek 1: Temel Test Sınıfı



import org.junit.jupiter.api.Test;

import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest

public class DemoApplicationTests {


    @Test

    void contextLoads() {

        // Bu test, uygulamanın başlatılıp başlatılmadığını kontrol eder.

    }

}



Bu basit test, Spring Boot uygulamanızın başarılı bir şekilde başlatılıp başlatılmadığını kontrol eder. Eğer bir yapılandırma hatası varsa, bu test başarısız olacaktır.


3. Service Katmanı için Birim Test


Gerçek dünyada, sadece uygulamanın başlatılıp başlatılmadığını değil, aynı zamanda iş mantığının doğru çalışıp çalışmadığını test etmek istersiniz. Bunun için, Mockito kullanarak bağımlılıkları sahte nesnelerle (mock) değiştirebilir ve sadece test edilmek istenen sınıfı izole edebilirsiniz.


Örnek 2: Service Sınıfı Testi


Bu örnekte, bir ProductService sınıfını ve onun ProductRepository ile olan bağımlılığını test ediyoruz. ProductRepository'yi Mockito ile sahte nesne olarak kullanacağız.


1. Service Sınıfı



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.Optional;


@Service

public class ProductService {


    private final ProductRepository productRepository;


    @Autowired

    public ProductService(ProductRepository productRepository) {

        this.productRepository = productRepository;

    }


    public Product getProductById(Long id) {

        return productRepository.findById(id).orElse(null);

    }

}



2. Repository Sınıfı



import org.springframework.data.jpa.repository.JpaRepository;


public interface ProductRepository extends JpaRepository<Product, Long> {

}



3. JUnit ve Mockito ile Test



import static org.junit.jupiter.api.Assertions.assertEquals;

import static org.mockito.Mockito.when;


import org.junit.jupiter.api.BeforeEach;

import org.junit.jupiter.api.Test;

import org.mockito.InjectMocks;

import org.mockito.Mock;

import org.mockito.MockitoAnnotations;


import java.util.Optional;


public class ProductServiceTest {


    @InjectMocks

    private ProductService productService;  // Test edeceğimiz sınıf


    @Mock

    private ProductRepository productRepository;  // Sahte repository


    @BeforeEach

    void setUp() {

        MockitoAnnotations.openMocks(this);  // Mockito'yu başlat

    }


    @Test

    void testGetProductById() {

        // Sahte veri oluşturuyoruz

        Product mockProduct = new Product();

        mockProduct.setId(1L);

        mockProduct.setName("Test Product");


        // Mockito'yu kullanarak sahte repository'yi yapılandırıyoruz

        when(productRepository.findById(1L)).thenReturn(Optional.of(mockProduct));


        // Servis metodunu test ediyoruz

        Product product = productService.getProductById(1L);


        // Beklenen sonuçları doğruluyoruz

        assertEquals(1L, product.getId());

        assertEquals("Test Product", product.getName());

    }

}



Açıklamalar:

  1. @InjectMocks: Test edilen sınıfın (bu örnekte ProductService) bağımlılıkları otomatik olarak enjekte edilir.
  2. @Mock: Sahte nesne oluşturur (bu örnekte ProductRepository). Bu sınıfı gerçek nesne yerine kullanırız.
  3. MockitoAnnotations.openMocks(this): Mockito'nun anotasyon tabanlı mock'ları başlatmasını sağlar.
  4. when(...).thenReturn(...): ProductRepository için bir sahte davranış tanımlıyoruz. Eğer findById(1L) çağrılırsa, mockProduct dönecek.
  5. assertEquals(...): Beklenen sonuç ile gerçek sonucu karşılaştırarak testin doğru çalışıp çalışmadığını kontrol eder.


4. Controller Katmanı için Test


Controller sınıflarını test etmek için Spring Boot'un sunduğu MockMvc sınıfını kullanabilirsiniz. MockMvc, Spring MVC'yi sahte bir ortamda test etmenize olanak tanır.


Örnek 3: Controller Testi


1. Controller Sınıfı



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

@RequestMapping("/api/products")

public class ProductController {


    @Autowired

    private ProductService productService;


    @GetMapping("/{id}")

    public ResponseEntity<Product> getProductById(@PathVariable Long id) {

        Product product = productService.getProductById(id);

        if (product != null) {

            return ResponseEntity.ok(product);

        } else {

            return ResponseEntity.notFound().build();

        }

    }

}



2. JUnit ve MockMvc ile Test



import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;


import org.junit.jupiter.api.BeforeEach;

import org.junit.jupiter.api.Test;

import org.mockito.InjectMocks;

import org.mockito.Mock;

import org.mockito.MockitoAnnotations;

import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;

import org.springframework.test.web.servlet.MockMvc;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.mock.mockito.MockBean;

import org.springframework.test.web.servlet.setup.MockMvcBuilders;


import java.util.Optional;


import static org.mockito.Mockito.when;


@WebMvcTest(ProductController.class)

public class ProductControllerTest {


    @Autowired

    private MockMvc mockMvc;


    @MockBean

    private ProductService productService;  // Sahte servis


    @Test

    void testGetProductById() throws Exception {

        // Sahte ürün

        Product mockProduct = new Product();

        mockProduct.setId(1L);

        mockProduct.setName("Test Product");


        // Servis metodunun nasıl davranacağını belirliyoruz

        when(productService.getProductById(1L)).thenReturn(mockProduct);


        // MockMvc kullanarak controller'ı test ediyoruz

        mockMvc.perform(get("/api/products/1"))

                .andExpect(status().isOk())

                .andExpect(jsonPath("$.name").value("Test Product"));

    }

}



Açıklamalar:

  1. @WebMvcTest: Sadece controller'ı test etmek için kullanılır. Diğer Spring bileşenleri yüklenmez.
  2. MockMvc: HTTP isteklerini simüle etmek için kullanılır.
  3. @MockBean: ProductService'i sahte bir nesne olarak tanımlar.
  4. mockMvc.perform(get(...)): HTTP GET isteği simüle edilir.
  5. jsonPath("$.name").value("Test Product"): JSON cevabındaki name alanının beklenen değeri test edilir.


Özet:

  • JUnit ve Mockito kullanarak Spring Boot uygulamalarının servis, repository ve controller katmanlarını kolayca test edebilirsiniz.
  • Mockito bağımlılıkları sahte nesneler (mock objects) ile taklit eder ve bağımlılıkların izolasyonunu sağlar.
  • MockMvc ile Spring MVC controller'larını HTTP isteklerini simüle ederek test edebilirsiniz.



16. Profil Yönetimi

  • Farklı application-{profile}.properties dosyaları oluşturarak farklı ortamlarda uygulamanızı çalıştırın.
  • 16. Profil Yönetimi


Spring Boot, farklı çalışma ortamları (development, test, production gibi) için profil yönetimi sunar. Profiller, uygulamanızın farklı yapılandırma dosyalarını kullanarak farklı ortamlarda çalışmasını sağlar. Her ortam için (geliştirme, test, üretim) farklı yapılandırmalar yapabilir ve bu profilleri etkinleştirerek ortam spesifik ayarlarla uygulamanızı çalıştırabilirsiniz.


Spring Boot’ta profiller, application-{profile}.properties veya application-{profile}.yml dosyaları kullanılarak yönetilir. Ayrıca default profil de oluşturabilirsiniz.


1. Profil Oluşturma


Farklı ortamlara göre Spring Boot uygulamanızın yapılandırmalarını ayırmak için, her profil için ayrı bir properties dosyası oluşturabilirsiniz. Örneğin:


  • application.properties: Genel ayarlar (varsayılan yapılandırma).
  • application-dev.properties: Geliştirme ortamı için ayarlar.
  • application-prod.properties: Üretim ortamı için ayarlar.


Örnek Yapılandırma Dosyaları:


1. application.properties (Genel Yapılandırma):

Bu dosya, varsayılan yapılandırma ayarlarını içerir ve herhangi bir profil belirtilmediğinde kullanılır.



spring.application.name=MyApp

spring.datasource.url=jdbc:h2:mem:testdb

spring.datasource.username=sa

spring.datasource.password=



2. application-dev.properties (Geliştirme Ortamı):

Bu dosya, geliştirme ortamı için özel ayarlar içerir.



# Geliştirme ortamı veri tabanı

spring.datasource.url=jdbc:mysql://localhost:3306/dev_db

spring.datasource.username=dev_user

spring.datasource.password=dev_password


# Hibernate ayarları

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true



3. application-prod.properties (Üretim Ortamı):

Bu dosya, üretim ortamı için özel ayarlar içerir.



# Üretim ortamı veri tabanı

spring.datasource.url=jdbc:mysql://localhost:3306/prod_db

spring.datasource.username=prod_user

spring.datasource.password=prod_password


# Hibernate ayarları

spring.jpa.hibernate.ddl-auto=validate

spring.jpa.show-sql=false


# Log seviyesi

logging.level.root=WARN



2. Profili Etkinleştirme


Spring Boot, varsayılan olarak application.properties dosyasını kullanır. Ancak belirli bir profil dosyasını etkinleştirerek, o profile ait yapılandırmaları kullanmasını sağlayabilirsiniz.


Profil Etkinleştirmenin Yolları:


  • Komut Satırı ile Profil Etkinleştirme:
    • Uygulamayı çalıştırırken komut satırından belirli bir profili etkinleştirebilirsiniz:



   mvn spring-boot:run -Dspring-boot.run.profiles=dev



veya



   java -jar myapp.jar --spring.profiles.active=prod



  • application.properties Dosyasında Profil Ayarı:
  • Genel yapılandırma dosyanızda aktif bir profil belirleyebilirsiniz:


  •    spring.profiles.active=dev


  • Bu, uygulamanız başlatıldığında otomatik olarak dev profilini kullanacaktır.

  • IDE Ayarlarında Profil Etkinleştirme:
    • IntelliJ IDEA veya Eclipse gibi IDE'lerde çalışma yapılandırmasında (Run/Debug Configurations) Active Profile kısmına dev, prod gibi profil isimlerini ekleyerek profili etkinleştirebilirsiniz.


3. Birden Fazla Profil Kullanma


Birden fazla profili aynı anda etkinleştirebilirsiniz. Örneğin, dev ve debug profillerini etkinleştirmek istiyorsanız:



java -jar myapp.jar --spring.profiles.active=dev,debug



Bu durumda, hem application-dev.properties hem de application-debug.properties dosyalarındaki ayarlar birleştirilir. Eğer aynı anahtarlar farklı dosyalarda tanımlanmışsa, en son yüklenen profilin ayarı geçerli olur.


4. Profile Özgü Bean Tanımları


Spring, profillere özgü bean tanımlamayı destekler. Bu sayede, bir bean'in belirli bir profil aktifken yüklenmesini sağlayabilirsiniz.


Örnek: Profil Bazlı Bean Tanımı



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Profile;


@Configuration

public class DataSourceConfig {


    @Bean

    @Profile("dev")

    public DataSource devDataSource() {

        return new DataSource("jdbc:mysql://localhost:3306/dev_db", "dev_user", "dev_password");

    }


    @Bean

    @Profile("prod")

    public DataSource prodDataSource() {

        return new DataSource("jdbc:mysql://localhost:3306/prod_db", "prod_user", "prod_password");

    }

}



  • @Profile("dev"): Bu bean sadece dev profili aktifken yüklenecektir.
  • @Profile("prod"): Bu bean sadece prod profili aktifken yüklenecektir.


5. Varsayılan Profil Kullanımı


Spring Boot'ta belirli bir profil aktif edilmezse, default profili devreye girer. Varsayılan profil dosyası application.properties veya application-default.properties olarak tanımlanabilir. Eğer başka bir profil etkinleştirilmemişse, Spring bu dosyayı kullanır.


6. Profil Bazlı Loglama Seviyesi Ayarı


Her profil için farklı loglama seviyeleri tanımlayabilirsiniz. Örneğin, geliştirme ortamında daha detaylı loglar görmek (DEBUG) isteyebilirken, üretim ortamında sadece kritik logları (ERROR, WARN) görmek isteyebilirsiniz.


Örnek: Profil Bazlı Loglama Seviyeleri


application-dev.properties:


logging.level.org.springframework=DEBUG

logging.level.com.example=DEBUG



application-prod.properties:


logging.level.org.springframework=WARN

logging.level.com.example=ERROR



7. Profil Bazlı Veri Tabanı Yapılandırması


Her ortamda farklı veri tabanları kullanmanız gerekiyorsa, bunu profiller aracılığıyla yönetebilirsiniz.


Örnek: Profil Bazlı Veri Tabanı Yapılandırması


application-dev.properties:


spring.datasource.url=jdbc:mysql://localhost:3306/dev_db

spring.datasource.username=dev_user

spring.datasource.password=dev_password



application-prod.properties:


spring.datasource.url=jdbc:mysql://localhost:3306/prod_db

spring.datasource.username=prod_user

spring.datasource.password=prod_password



8. YML ile Profil Yönetimi


Eğer YML dosyalarını tercih ediyorsanız, profillere özel YML dosyaları da oluşturabilirsiniz.


application.yml:


spring:

  profiles:

    active: dev  # Varsayılan aktif profil


---

spring:

  profiles: dev

  datasource:

    url: jdbc:mysql://localhost:3306/dev_db

    username: dev_user

    password: dev_password


---

spring:

  profiles: prod

  datasource:

    url: jdbc:mysql://localhost:3306/prod_db

    username: prod_user

    password: prod_password



Özet:

  • Profiller, Spring Boot uygulamanızın farklı ortamlarda (development, test, production) farklı yapılandırmalarla çalışmasını sağlar.
  • Profil dosyaları application-{profile}.properties ya da application-{profile}.yml şeklinde oluşturulabilir.
  • Farklı profilleri komut satırından, application.properties dosyasından ya da IDE'den etkinleştirebilirsiniz.
  • Her profil için farklı bean'ler tanımlayabilir ve profil bazlı yapılandırmalar (veri tabanı ayarları, log seviyeleri vb.) yapabilirsiniz.


Spring Boot profilleri ile uygulamanızı esnek ve çevik bir şekilde farklı ortamlarda çalıştırabilirsiniz.


17. Custom Endpoints ve Metrics

17. Custom Endpoints ve Metrics


Spring Boot Actuator, uygulamanızın sağlık durumu ve performansını izlemek için önceden tanımlanmış bir dizi uç nokta (endpoint) sağlar. Bunun yanı sıra, kendi özel uç noktalarınızı (custom endpoints) oluşturabilir ve uygulamanıza özgü metrikler ekleyebilirsiniz. Bu metrikler, uygulamanızın özel performans ölçümlerini ya da işlevsel durumlarını izlemek için kullanılabilir.


1. Custom Actuator Endpoint Oluşturma


Spring Boot, @Endpoint anotasyonu ile özel uç noktalar tanımlamanıza olanak tanır. Özel bir Actuator uç noktası oluşturarak, uygulamanızdan istediğiniz verileri döndürebilirsiniz.


Örnek: Basit Özel Actuator Uç Noktası



import org.springframework.boot.actuate.endpoint.annotation.Endpoint;

import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;

import org.springframework.stereotype.Component;


@Component

@Endpoint(id = "customEndpoint")

public class CustomEndpoint {


    @ReadOperation

    public String customMetric() {

        return "Custom metric";

    }

}



Açıklamalar:

  1. @Endpoint(id = "customEndpoint"): Bu anotasyon, özel bir Actuator uç noktası tanımlar. Bu örnekte, /actuator/customEndpoint URL'sinde erişilebilecek bir uç nokta oluşturulmuştur.
  2. @ReadOperation: Bu anotasyon, bir HTTP GET isteği ile bu uç noktaya erişileceğini belirtir. Diğer işlemler için @WriteOperation (POST, PUT) veya @DeleteOperation (DELETE) anotasyonları kullanılabilir.
  3. return "Custom metric";: Bu uç nokta her çağrıldığında basit bir metin döner. Gerçek dünyada, burada özel metrikler veya uygulama durumu gibi bilgiler döndürebilirsiniz.


Uç Noktayı Test Etme:

Uygulamanızı başlattıktan sonra tarayıcı veya Postman gibi bir araçla http://localhost:8080/actuator/customEndpoint adresine istek yaparak bu özel uç noktaya erişebilirsiniz.



curl http://localhost:8080/actuator/customEndpoint



Yanıt:


Custom metric



2. Metriklerin Toplanması - MeterRegistry


Spring Boot Actuator, uygulamanıza özgü metrikleri toplamak için MeterRegistry API'si sunar. Özel metrikler (sayım, zamanlama, vb.) oluşturmak ve bu metrikleri Prometheus, Graphite gibi sistemlere göndermek için kullanılabilir.


Örnek: Özel Metrik Oluşturma



import io.micrometer.core.instrument.MeterRegistry;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;


@Component

public class CustomMetrics {


    private final MeterRegistry meterRegistry;


    @Autowired

    public CustomMetrics(MeterRegistry meterRegistry) {

        this.meterRegistry = meterRegistry;

        registerCustomMetrics();

    }


    public void registerCustomMetrics() {

        // Özel bir sayaç (counter) tanımlıyoruz

        meterRegistry.counter("custom_metric_counter").increment();


        // Özel bir gauge (anlık değer) tanımlıyoruz

        meterRegistry.gauge("custom_metric_gauge", Math.random() * 100);

    }

}



Açıklamalar:

  1. MeterRegistry: Spring Boot'ta metriklerin kaydedilmesi için kullanılan sınıftır. Bu sınıf, sayılar, zamanlayıcılar ve diğer metrikleri yönetir.
  2. counter("custom_metric_counter"): Bir sayaç tanımlar ve her çalıştırıldığında sayacı artırır.
  3. gauge("custom_metric_gauge", ...): Anlık bir değer ölçümü sağlar. Bu örnekte rastgele bir sayı ölçülmektedir.


Metrikleri Test Etme:

Metrikler Actuator’ın /actuator/metrics uç noktası üzerinden izlenebilir. Tarayıcıda http://localhost:8080/actuator/metrics/custom_metric_counter adresine istek göndererek, sayacı görüntüleyebilirsiniz.



curl http://localhost:8080/actuator/metrics/custom_metric_counter



Yanıt:


{

  "name": "custom_metric_counter",

  "measurements": [

    {

      "statistic": "COUNT",

      "value": 1.0

    }

  ],

  "availableTags": []

}



Benzer şekilde, gauge için de metrikleri izleyebilirsiniz:



curl http://localhost:8080/actuator/metrics/custom_metric_gauge



Yanıt:


{

  "name": "custom_metric_gauge",

  "measurements": [

    {

      "statistic": "VALUE",

      "value": 72.34

    }

  ],

  "availableTags": []

}



3. Actuator İle Metrik İzleme


Actuator’ın varsayılan metrik uç noktaları uygulamanızın performansını izlemenize yardımcı olur. Varsayılan olarak gelen uç noktalarla CPU, bellek kullanımı, HTTP istekleri, GC (garbage collection) gibi metrikleri izleyebilirsiniz.


Varsayılan metrik uç noktaları:

  • /actuator/metrics: Tüm metrikleri listeler.
  • /actuator/metrics/{metricName}: Belirli bir metriği gösterir. Örneğin, HTTP istek sayısını görmek için: /actuator/metrics/http.server.requests.


4. application.properties ile Actuator Yapılandırması


application.properties dosyasında özel uç noktaları ve metrikleri etkinleştirmek veya özelleştirmek için şu ayarları ekleyebilirsiniz:



# Tüm Actuator uç noktalarını etkinleştir

management.endpoints.web.exposure.include=*


# Sağlık detaylarını göster

management.endpoint.health.show-details=always



5. Prometheus ve Grafana ile Metrik İzleme


Spring Boot Actuator ile topladığınız özel metrikleri Prometheus gibi bir izleme sistemi ile entegre edebilir ve Grafana ile görselleştirebilirsiniz.


Prometheus Bağımlılığı:



<dependency>

    <groupId>io.micrometer</groupId>

    <artifactId>micrometer-registry-prometheus</artifactId>

</dependency>



Bu bağımlılık, uygulamanızın metriklerini Prometheus formatında sunar. Prometheus sunucusu bu metrikleri belirli aralıklarla toplayarak izleme işlemini gerçekleştirir.


Özet:

  • Custom Endpoints ve Custom Metrics, Spring Boot Actuator ile özelleştirilmiş izleme ve yönetim işlevleri oluşturmanızı sağlar.
  • @Endpoint anotasyonu ile kendi özel uç noktalarınızı tanımlayabilir, MeterRegistry ile özelleştirilmiş metrikler oluşturabilirsiniz.
  • Actuator ile uygulamanızın performansını ve sağlık durumunu izlemek için mevcut metrik uç noktalarını da kullanabilirsiniz.
  • Metrikleri Prometheus ve Grafana ile entegre ederek, daha kapsamlı ve görsel olarak takip edebilirsiniz.


Bu özellikler sayesinde Spring Boot uygulamanızı izlemek ve yönetmek çok daha esnek ve güçlü hale gelir.

18. Spring Boot Security

18. Spring Boot Security


Spring Security, Spring Boot uygulamalarına güvenlik katmanı eklemek için kullanılan güçlü bir kütüphanedir. Bu kütüphane, kimlik doğrulama (authentication), yetkilendirme (authorization), şifreleme ve güvenlik tehditlerine karşı koruma sağlar. Spring Boot uygulamalarında güvenliği sağlamak için spring-boot-starter-security bağımlılığını ekleyerek hızlı bir başlangıç yapabilirsiniz.


1. Spring Security Bağımlılığını Eklemek


İlk adım olarak, Spring Boot uygulamanıza spring-boot-starter-security bağımlılığını ekleyin.


pom.xml Bağımlılığı:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-security</artifactId>

</dependency>



Bu bağımlılığı ekledikten sonra Spring Boot, varsayılan güvenlik yapılandırmalarını otomatik olarak etkinleştirir.


2. Varsayılan Spring Security Davranışı


Spring Boot Security eklendiğinde, varsayılan olarak şu güvenlik özellikleri etkinleşir:

  • Tüm HTTP uç noktaları güvenlik altına alınır (kimlik doğrulama gerektirir).
  • Varsayılan olarak kullanıcı adı user, şifre ise her uygulama başlatıldığında rastgele olarak üretilir ve konsola yazdırılır.
  • Basic Authentication mekanizması kullanılır.


Konsol Çıktısı (Varsayılan Şifre):


Using generated security password: 3b98e6f8-2a65-4baf-aab2-1234567890ab



Bu şifre ile, uygulamanın korunan tüm uç noktalarına erişim sağlamak için varsayılan user kullanıcı adı ile giriş yapabilirsiniz.


3. Spring Security Yapılandırması


Varsayılan ayarları değiştirmek ve özel güvenlik yapılandırması yapmak için bir SecurityConfig sınıfı oluşturabilirsiniz.


Örnek: Temel Güvenlik Yapılandırması



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.core.userdetails.User;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import org.springframework.security.web.SecurityFilterChain;


@Configuration

public class SecurityConfig {


    @Bean

    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http

            .authorizeRequests()

                .antMatchers("/public/**").permitAll() // /public altında olan tüm sayfalara erişime izin ver

                .anyRequest().authenticated() // Diğer tüm istekler için kimlik doğrulaması iste

            .and()

            .formLogin() // Form tabanlı kimlik doğrulamayı etkinleştir

                .permitAll()

            .and()

            .logout() // Çıkış yapma özelliğini etkinleştir

                .permitAll();


        return http.build();

    }


    @Bean

    public UserDetailsService userDetailsService() {

        UserDetails user = User.withDefaultPasswordEncoder() // Varsayılan şifreleme ile kullanıcı oluştur

            .username("user")

            .password("password")

            .roles("USER")

            .build();


        UserDetails admin = User.withDefaultPasswordEncoder()

            .username("admin")

            .password("admin")

            .roles("ADMIN")

            .build();


        return new InMemoryUserDetailsManager(user, admin);

    }

}



Açıklamalar:

  • SecurityFilterChain: Spring Security'nin filtre zincirini yapılandırır. Hangi URL'lere kimlik doğrulaması gerektiğini veya izin verileceğini burada belirleyebilirsiniz.
    • antMatchers("/public/**").permitAll(): /public ile başlayan URL'lere erişim için kimlik doğrulama gerektirmez.
    • anyRequest().authenticated(): Diğer tüm URL'ler için kimlik doğrulaması zorunlu kılınır.
  • formLogin(): Form tabanlı kimlik doğrulama etkinleştirilir. Bu, kullanıcı adı ve şifre ile giriş yapılan bir form sayfasını oluşturur.
  • userDetailsService(): Bellek içi (in-memory) bir kullanıcı veritabanı oluşturulur ve iki kullanıcı tanımlanır:
    • user: Şifre password ve USER rolüne sahip.
    • admin: Şifre admin ve ADMIN rolüne sahip.


4. Spring Security ile Kimlik Doğrulama (Authentication)


Kimlik doğrulama (authentication), kullanıcıların uygulamaya erişim sağlamak için kimlik bilgilerini (kullanıcı adı ve şifre) kullanarak doğrulanmasını sağlar. Yukarıdaki örnekte, kimlik doğrulama için form tabanlı giriş sistemi tanımlanmıştır.


Form Login:

  • Uygulamanızda herhangi bir korunan URL'ye erişmeye çalıştığınızda, kullanıcı adı ve şifre girmeniz için bir giriş formu göreceksiniz.


URL: http://localhost:8080/login


  • Varsayılan olarak, kimlik doğrulaması başarılı olduğunda ana sayfaya veya giriş yapmadan önce erişmeye çalıştığınız sayfaya yönlendirilirsiniz.


5. Spring Security ile Yetkilendirme (Authorization)


Yetkilendirme (authorization), kimlik doğrulaması yapılan kullanıcının hangi kaynaklara ve işlemlere erişebileceğini kontrol eder. Roller ve yetkiler kullanılarak kullanıcıların farklı erişim seviyelerine sahip olması sağlanır.


Yetkilendirme Örneği:


Yukarıdaki yapılandırmada, kullanıcılar USER ve ADMIN rollerine sahiptir. Aşağıdaki örnekte, sadece ADMIN rolüne sahip kullanıcıların belirli bir URL'ye erişmesini sağlayabiliriz:



http

    .authorizeRequests()

        .antMatchers("/admin/**").hasRole("ADMIN")  // Sadece ADMIN rolündeki kullanıcılar erişebilir

        .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")  // USER veya ADMIN rolündeki kullanıcılar erişebilir

        .anyRequest().authenticated();



6. Şifrelerin Şifrelenmesi


Spring Security, şifrelerin güvenliğini sağlamak için güçlü şifreleme mekanizmaları sunar. Yukarıdaki örnekte withDefaultPasswordEncoder() kullanılarak basit bir şifreleme uygulanmıştır. Üretim ortamında daha güçlü bir şifreleme algoritması kullanmanız önerilir.


Şifreleme İçin BCrypt Kullanımı:



import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.crypto.password.PasswordEncoder;


@Bean

public PasswordEncoder passwordEncoder() {

    return new BCryptPasswordEncoder();

}



Şifreleri bu şifreleyici ile hashleyip güvenli bir şekilde saklayabilirsiniz:



UserDetails user = User.builder()

    .username("user")

    .password(passwordEncoder().encode("password"))

    .roles("USER")

    .build();



7. SecurityConfig Sınıfını Özelleştirme


Spring Security yapılandırmasını daha da özelleştirebilirsiniz. Örneğin, belirli sayfalara veya API'lere erişim izni tanımlayabilir, özel login ve logout sayfaları oluşturabilirsiniz.


Özel Login Sayfası:



http

    .formLogin()

        .loginPage("/custom-login")  // Özel bir login sayfası tanımlanır

        .permitAll();



Özel Logout İşlemi:



http

    .logout()

        .logoutUrl("/custom-logout")

        .logoutSuccessUrl("/login?logout")

        .permitAll();



8. CSRF Koruması


Spring Security, CSRF (Cross-Site Request Forgery) saldırılarına karşı koruma sağlar. CSRF koruması, form tabanlı işlemler için otomatik olarak etkindir. Ancak, API'ler gibi durumlarda bu koruma devre dışı bırakılabilir:



http

    .csrf().disable();  // CSRF korumasını devre dışı bırakır



Özet:

  • Spring Boot Security, uygulamanızı hızlıca güvenli hale getirir ve kimlik doğrulama (authentication) ile yetkilendirme (authorization) sağlar.
  • Varsayılan güvenlik yapılandırması, tüm uç noktaları koruma altına alır ve form tabanlı kimlik doğrulama sunar.
  • SecurityConfig sınıfı ile güvenlik yapılandırmasını özelleştirebilir, kullanıcıların rollerine göre yetkilendirme yapabilirsiniz.
  • Kullanıcı şifreleri güçlü bir şekilde şifrelenmeli, örneğin BCrypt ile hashlenmelidir.


Spring Boot Security ile uygulamanızda güçlü bir güvenlik katmanı ekleyerek, güvenli ve kontrollü bir kullanıcı erişim sistemi sağlayabilirsiniz.

19. JWT ile Authentication (Kimlik Doğrulama)

  • JWT kullanarak kimlik doğrulama işlemi yapın.
  • 19. JWT ile Authentication (Kimlik Doğrulama)


JWT (JSON Web Token), stateless kimlik doğrulama mekanizması sağlamak için kullanılan bir standarttır. JWT ile bir kullanıcı kimlik doğrulandıktan sonra, bu kullanıcıya bir token verilir ve sonraki tüm isteklerde bu token kullanılarak kimlik doğrulama yapılır. Bu yöntem, özellikle mikroservis mimarisi veya RESTful API'lerde yaygın olarak kullanılır çünkü her istekte sunucuya kimlik bilgileri gönderilmez, bunun yerine token kullanılır.


1. JWT Nedir?


JWT (JSON Web Token), üç ana parçadan oluşur:

  1. Header (Başlık): Token'ın türünü (JWT) ve kullanılan şifreleme algoritmasını içerir.
  2. Payload (Yük): Kimlik doğrulama ve yetkilendirme bilgilerini taşır. Örneğin, kullanıcı bilgileri ve token'ın süresi.
  3. Signature (İmza): Token'ın bütünlüğünü sağlamak için header ve payload'un birleştirilmiş hali, gizli bir anahtar kullanılarak imzalanır.


JWT yapısı şu şekildedir:


header.payload.signature



JWT, base64 URL-safe formatında kodlanır, bu nedenle tarayıcı ve HTTP isteğiyle güvenli bir şekilde iletilebilir.


2. JWT ile Kimlik Doğrulama Akışı


JWT tabanlı kimlik doğrulama genel olarak şu şekilde çalışır:

  1. Kullanıcı, sunucuya kullanıcı adı ve şifresi ile kimlik doğrulama isteği gönderir.
  2. Sunucu, kullanıcının kimliğini doğrularsa, ona bir JWT token oluşturup geri döner.
  3. Kullanıcı, sonraki tüm isteklerde JWT token'ı sunucuya gönderir.
  4. Sunucu, her istek geldiğinde JWT token'ını doğrular ve isteğin geçerli olup olmadığını kontrol eder.
  5. JWT token süresi dolduğunda kullanıcı tekrar giriş yaparak yeni bir token alır.


3. JWT ile Spring Boot Uygulaması


Spring Boot uygulamasında JWT tabanlı kimlik doğrulama mekanizması kurmak için şu adımları izleyebilirsiniz:


Adım 1: Gerekli Bağımlılıkları Ekleyin


pom.xml dosyanıza spring-boot-starter-security ve jjwt bağımlılığını ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-security</artifactId>

</dependency>

<dependency>

    <groupId>io.jsonwebtoken</groupId>

    <artifactId>jjwt</artifactId>

    <version>0.9.1</version>

</dependency>



Adım 2: JWT Token Oluşturma


Kullanıcı kimlik doğrulandıktan sonra JWT token oluşturmak için bir yardımcı sınıf yazabilirsiniz.


JwtTokenUtil: JWT token oluşturma ve doğrulama işlemlerini içerir.



import io.jsonwebtoken.Jwts;

import io.jsonwebtoken.SignatureAlgorithm;

import org.springframework.stereotype.Component;


import java.util.Date;

import java.util.HashMap;

import java.util.Map;


@Component

public class JwtTokenUtil {


    private String SECRET_KEY = "mySecretKey"; // Gizli anahtar


    // Token oluşturma

    public String generateToken(String username) {

        Map<String, Object> claims = new HashMap<>();

        return createToken(claims, username);

    }


    // Token'ı oluşturup geri döner

    private String createToken(Map<String, Object> claims, String subject) {

        return Jwts.builder()

                .setClaims(claims)

                .setSubject(subject)  // Kullanıcı adı gibi kimlik bilgisi

                .setIssuedAt(new Date(System.currentTimeMillis())) // Token oluşturulma zamanı

                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // Token geçerlilik süresi (10 saat)

                .signWith(SignatureAlgorithm.HS256, SECRET_KEY) // İmza algoritması

                .compact();

    }


    // Token'dan kullanıcı adını alır

    public String extractUsername(String token) {

        return Jwts.parser()

                .setSigningKey(SECRET_KEY)

                .parseClaimsJws(token)

                .getBody()

                .getSubject();

    }


    // Token geçerliliğini kontrol eder

    public boolean isTokenValid(String token, String username) {

        String extractedUsername = extractUsername(token);

        return (extractedUsername.equals(username) && !isTokenExpired(token));

    }


    // Token süresinin dolup dolmadığını kontrol eder

    private boolean isTokenExpired(String token) {

        return Jwts.parser()

                .setSigningKey(SECRET_KEY)

                .parseClaimsJws(token)

                .getBody()

                .getExpiration()

                .before(new Date());

    }

}



Adım 3: Kullanıcı Giriş İşlemi ve Token Döndürme


Kullanıcı giriş yaptıktan sonra ona bir JWT token döndüren bir AuthController oluşturun.


AuthController:



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.AuthenticationException;

import org.springframework.web.bind.annotation.*;


@RestController

@RequestMapping("/auth")

public class AuthController {


    @Autowired

    private AuthenticationManager authenticationManager;


    @Autowired

    private JwtTokenUtil jwtTokenUtil;


    @PostMapping("/login")

    public String login(@RequestBody AuthRequest authRequest) throws Exception {

        try {

            authenticationManager.authenticate(

                new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())

            );

        } catch (AuthenticationException e) {

            throw new Exception("Invalid username or password");

        }

        return jwtTokenUtil.generateToken(authRequest.getUsername());

    }

}


class AuthRequest {

    private String username;

    private String password;


    // Getters and Setters

}



Bu controller, giriş bilgileri doğru ise bir JWT token döner. 


Adım 4: JWT'yi Doğrulama


Her gelen istekte JWT token'ını doğrulamak için JwtRequestFilter adlı bir filtre eklemeniz gerekir.


JwtRequestFilter:



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;

import org.springframework.stereotype.Component;

import org.springframework.web.filter.OncePerRequestFilter;

import io.jsonwebtoken.ExpiredJwtException;


import javax.servlet.FilterChain;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


@Component

public class JwtRequestFilter extends OncePerRequestFilter {


    @Autowired

    private JwtTokenUtil jwtTokenUtil;


    @Autowired

    private UserDetailsService userDetailsService;


    @Override

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {

        final String authorizationHeader = request.getHeader("Authorization");


        String username = null;

        String jwt = null;


        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {

            jwt = authorizationHeader.substring(7);

            try {

                username = jwtTokenUtil.extractUsername(jwt);

            } catch (ExpiredJwtException e) {

                // Token expired

            }

        }


        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);


            if (jwtTokenUtil.isTokenValid(jwt, userDetails.getUsername())) {

                UsernamePasswordAuthenticationToken authenticationToken = 

                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(authenticationToken);

            }

        }

        chain.doFilter(request, response);

    }

}



Adım 5: Güvenlik Yapılandırması


Son olarak, SecurityConfig sınıfınızı JWT kullanacak şekilde yapılandırın.


SecurityConfig:



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.http.SessionCreationPolicy;

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import org.springframework.security.web.SecurityFilterChain;


@Configuration

@EnableWebSecurity

public class SecurityConfig {


    @Autowired

    private JwtRequestFilter jwtRequestFilter;


    @Bean

    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.csrf().disable()

            .authorizeRequests().antMatchers("/auth/login").permitAll()

            .anyRequest().authenticated()

            .and()

            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);


        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);


        return http.build();

    }


    @Bean

    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {

        return http.getSharedObject(AuthenticationManagerBuilder.class).build();

    }

}



6. JWT Token ile Güvenli İstekler Yapmak


JWT token'ı doğrulamak ve kullanmak için tüm isteklerde Authorization başlığında bu token'ı iletmeniz gerekmektedir. Token, genellikle Bearer tipi ile gönderilir.


İstek Gönderme (JWT Token ile)


Kullanıcı giriş yaptıktan ve JWT token'ı aldıktan sonra, bu token'ı her HTTP isteğinde kullanarak kimlik doğrulama yapabilirsiniz. Aşağıda bir örnek HTTP isteği gösterilmektedir:



GET /api/protected-endpoint HTTP/1.1

Host: localhost:8080

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNjIyNzU3NzQ3fQ.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ



  • Authorization başlığı ile Bearer tipi ve token gönderilir.
  • Sunucu, token'ı alıp doğruladıktan sonra kullanıcının isteğini işleyebilir.


7. JWT Token Geçerlilik Süresi ve Yenileme


Bir JWT token belirli bir süre için geçerlidir. Token süresi dolduğunda, kullanıcı tekrar giriş yaparak yeni bir token almalıdır. Ancak bu süreci iyileştirmek için bir "refresh token" mekanizması da ekleyebilirsiniz.


Token Süresi Kontrolü


JwtTokenUtil sınıfında token süresini kontrol etmek için bir metot zaten eklenmişti. Bu metot, token'ın süresinin dolup dolmadığını kontrol eder:



private boolean isTokenExpired(String token) {

    return Jwts.parser()

               .setSigningKey(SECRET_KEY)

               .parseClaimsJws(token)

               .getBody()

               .getExpiration()

               .before(new Date());

}



Refresh Token Mekanizması


"Refresh token" kullanarak, erişim token'ının süresi dolduğunda kullanıcıdan tekrar giriş yapmasını istemeden yeni bir JWT token oluşturabilirsiniz. Refresh token'lar genellikle daha uzun süreli olur ve ayrı bir endpoint üzerinden yeni erişim token'ı almak için kullanılır.


Örneğin, bir /auth/refresh endpoint'i oluşturarak refresh token aracılığıyla yeni JWT token sağlayabilirsiniz:



@RestController

@RequestMapping("/auth")

public class AuthController {


    @PostMapping("/refresh")

    public String refreshToken(HttpServletRequest request) {

        String refreshToken = request.getHeader("Authorization").substring(7);

        // Token doğrulama işlemleri

        String newAccessToken = jwtTokenUtil.generateToken(jwtTokenUtil.extractUsername(refreshToken));

        return newAccessToken;

    }

}



8. Sonuç: JWT ile Güvenli Kimlik Doğrulama


JWT, kimlik doğrulama ve yetkilendirme süreçlerinde stateful bir oturum yönetimine gerek duymadan stateless bir yapıda güvenlik sağlamaktadır. Spring Boot ile JWT'yi kullanarak uygulamanızın güvenliğini artırabilir, her HTTP isteğinde token kullanarak kimlik doğrulaması yapabilirsiniz.


JWT'nin Avantajları:

  • Stateless: Sunucuda oturum bilgisi tutmadan doğrulama yapılabilir.
  • Ölçeklenebilirlik: Mikroservisler ve RESTful API'ler için idealdir, çünkü her servisin oturum bilgisini takip etmesi gerekmez.
  • Güvenli: İmza ve şifreleme ile token'lar güvenli hale getirilir. Token'ın içeriği değiştirilse bile sunucu bu durumu tespit edebilir.


JWT ile Kimlik Doğrulamanın Temel Adımları:

  1. Kullanıcı adı ve şifre ile kimlik doğrulama yapılır.
  2. Başarılı kimlik doğrulaması sonucunda JWT token oluşturulur ve kullanıcıya döner.
  3. Kullanıcı, token'ı sonraki tüm isteklerde Authorization: Bearer <token> başlığıyla gönderir.
  4. Sunucu, her istekte gelen token'ı doğrular ve işlemi gerçekleştirir.


9. Sonraki Adımlar


  • Refresh Token Kullanımı: Token yenileme işlemleri için refresh token mekanizması ekleyin.
  • Token Revocation (Geri Alım): Kullanıcı oturumunu sonlandırmak veya token'ları geçersiz kılmak için token kara listeleme (blacklisting) yapın.
  • Token Güvenliği: Token süresini çok uzun tutmayın ve güvenli bir gizli anahtar (secret key) kullanın.
  • OAuth2 ve JWT: JWT'yi OAuth2 protokolüyle birlikte kullanarak üçüncü taraf kimlik doğrulama hizmetlerine (Google, Facebook vb.) entegrasyon yapabilirsiniz.


JWT ile kimlik doğrulama, modern web ve mobil uygulamalarda yaygın olarak kullanılan, güvenli ve ölçeklenebilir bir çözümdür.


20. Swagger İle API Dokümantasyonu

20. Swagger ile API Dokümantasyonu


Swagger, REST API'lerinizi dokümante etmek ve test etmek için kullanılan popüler bir araçtır. Swagger, API'lerinizi hem makine hem de insan tarafından anlaşılabilir bir formatta tanımlamanızı sağlar. Spring Boot ile Swagger entegrasyonu oldukça basittir ve Springfox kütüphanesi kullanılarak API dokümantasyonları oluşturulabilir.


1. Swagger Bağımlılığını Eklemek


Swagger'ı Spring Boot projenize entegre etmek için springfox-boot-starter bağımlılığını eklemeniz gerekmektedir. pom.xml dosyanıza şu bağımlılığı ekleyin:



<dependency>

    <groupId>io.springfox</groupId>

    <artifactId>springfox-boot-starter</artifactId>

    <version>3.0.0</version>

</dependency>



Bu bağımlılık, Swagger'ın Spring Boot uygulamanızla kolayca entegre olmasını sağlar.


2. Swagger Yapılandırması


Swagger'ı Spring Boot uygulamanızda etkinleştirmek için genellikle bir yapılandırma sınıfı oluşturmanız gerekmez. Ancak daha özelleştirilmiş ayarlar yapmak isterseniz, Swagger için bir yapılandırma sınıfı ekleyebilirsiniz.


Örnek Swagger Yapılandırma Sınıfı (Opsiyonel):



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.PathSelectors;

import springfox.documentation.builders.RequestHandlerSelectors;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spring.web.plugins.Docket;

import springfox.documentation.swagger2.annotations.EnableSwagger2;


@Configuration

@EnableSwagger2

public class SwaggerConfig {


    @Bean

    public Docket api() {

        return new Docket(DocumentationType.SWAGGER_2)

                .select()

                .apis(RequestHandlerSelectors.basePackage("com.example"))

                .paths(PathSelectors.any())

                .build();

    }

}



Açıklamalar:

  1. @EnableSwagger2: Swagger 2'nin etkinleştirildiğini belirtir. Ancak Springfox 3.0.0 ve sonrası için bu anotasyon zorunlu değildir.
  2. Docket: Swagger yapılandırmasını tanımlayan bir bileşendir.
    • apis(RequestHandlerSelectors.basePackage("com.example")): API'nin sadece belirli bir paketteki controller'lar için dokümantasyon üretmesini sağlar.
    • paths(PathSelectors.any()): API'nin tüm yolları (endpoint'leri) için dokümantasyon oluşturulacağını belirtir.


Bu yapılandırma, uygulamanızın tüm REST API uç noktalarını (endpoints) Swagger ile dokümante eder.


3. Swagger Arayüzüne Erişme


Uygulamanızı başlattıktan sonra, Swagger dokümantasyon arayüzüne şu adres üzerinden erişebilirsiniz:



http://localhost:8080/swagger-ui/



Bu URL, Spring Boot uygulamanızın Swagger arayüzünü açar ve API'nizin tüm uç noktalarını görsel olarak test etmenizi sağlar.


4. Swagger Dokümantasyonunu Özelleştirme


Swagger dokümantasyonunu daha ayrıntılı hale getirmek için controller'larınıza ve API metotlarınıza açıklamalar ekleyebilirsiniz. Spring Boot uygulamanızdaki API metotlarınıza @ApiOperation ve @ApiParam gibi açıklama anotasyonları ekleyerek Swagger dokümantasyonunu zenginleştirebilirsiniz.


Örnek: Controller Metoduna Swagger Açıklamaları Eklemek



import io.swagger.annotations.Api;

import io.swagger.annotations.ApiOperation;

import io.swagger.annotations.ApiParam;

import org.springframework.web.bind.annotation.*;


@RestController

@RequestMapping("/api/products")

@Api(value = "Product Management System", tags = {"Product"})

public class ProductController {


    @GetMapping("/{id}")

    @ApiOperation(value = "Get product by ID", notes = "Provide an ID to look up a specific product")

    public Product getProductById(

            @ApiParam(value = "ID value for the product you want to retrieve", required = true)

            @PathVariable Long id) {

        return new Product(id, "Sample Product", 100.0);

    }


    @PostMapping

    @ApiOperation(value = "Create a new product")

    public Product createProduct(

            @ApiParam(value = "Product object to be created", required = true)

            @RequestBody Product product) {

        return product; // Basitçe geriye döner (örnek amaçlı)

    }

}



Açıklamalar:

  • @Api: Controller sınıfına genel bir açıklama eklemek için kullanılır.
    • value: Controller'ın ne için kullanıldığını açıklar.
    • tags: API kategorilerini belirtir.
  • @ApiOperation: Belirli bir API metodu için açıklama ekler. API'nin amacını, nasıl çalıştığını ve hangi bilgileri döndüreceğini belirtir.
  • @ApiParam: Metot parametrelerine açıklamalar ekler. Bu açıklamalar Swagger arayüzünde kullanıcıya gösterilir.


5. Swagger Kullanarak API Test Etme


Swagger arayüzü üzerinden API'nizi kolayca test edebilirsiniz:

  1. Swagger arayüzünde her API için bir "Try it out" butonu bulunur.
  2. Bu butona tıklayarak ilgili API uç noktasını seçip gerekli parametreleri doldurarak API'nizi test edebilirsiniz.


6. Swagger Güvenlik Yapılandırması


Eğer API'nizde JWT veya başka bir kimlik doğrulama yöntemi kullanıyorsanız, Swagger'da bu kimlik doğrulama mekanizmasını kullanarak API'lerinizi test edebilirsiniz.


JWT İçin Swagger'da Authorization Eklemek


Swagger arayüzüne JWT Bearer Token ile yetkilendirme ekleyebilirsiniz. Bunun için Swagger yapılandırma sınıfınıza şu ayarları ekleyin:



import springfox.documentation.service.ApiKey;

import springfox.documentation.service.AuthorizationScope;

import springfox.documentation.service.SecurityReference;

import springfox.documentation.spi.service.contexts.SecurityContext;


import java.util.List;


@Configuration

public class SwaggerConfig {


    @Bean

    public Docket api() {

        return new Docket(DocumentationType.SWAGGER_2)

                .securityContexts(List.of(securityContext()))

                .securitySchemes(List.of(apiKey()))

                .select()

                .apis(RequestHandlerSelectors.basePackage("com.example"))

                .paths(PathSelectors.any())

                .build();

    }


    private ApiKey apiKey() {

        return new ApiKey("JWT", "Authorization", "header");

    }


    private SecurityContext securityContext() {

        return SecurityContext.builder().securityReferences(defaultAuth()).build();

    }


    private List<SecurityReference> defaultAuth() {

        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");

        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];

        authorizationScopes[0] = authorizationScope;

        return List.of(new SecurityReference("JWT", authorizationScopes));

    }

}



Açıklamalar:

  1. apiKey(): JWT token'ını Authorization başlığına eklemek için kullanılır.
  2. securityContext(): JWT'nin Swagger dokümantasyonunda kullanılmasını sağlar.


Swagger arayüzünde sağ üst köşede bir Authorize butonu belirir. Bu butona tıklayarak JWT token'ınızı girebilir ve token ile korunan uç noktaları test edebilirsiniz.


7. Swagger URL ve API Dokümantasyonu


Swagger arayüzünün yanı sıra, Swagger tarafından üretilen OpenAPI (eski adıyla Swagger 2.0) JSON dokümantasyonu da mevcuttur. Bu dokümantasyona aşağıdaki URL'ler üzerinden erişebilirsiniz:

  • Swagger UI: http://localhost:8080/swagger-ui/
  • Swagger JSON: http://localhost:8080/v2/api-docs


8. Swagger Arayüzünü Özelleştirme


Swagger arayüzü varsayılan olarak gelir, ancak özelleştirmek isterseniz application.properties dosyanıza bazı ayarlar ekleyebilirsiniz:



springfox.documentation.swagger-ui.enabled=true

springfox.documentation.swagger-ui.path=/swagger-ui/



Ayrıca, Swagger dokümantasyonunu sadece belirli ortamlarda (örneğin, development) etkinleştirmek isteyebilirsiniz. Bunu profillere göre yapılandırabilirsiniz:



@Configuration

@Profile("dev")

public class SwaggerConfig {

    // Swagger yapılandırması sadece development profilinde etkin olur

}



Özet:

  • Swagger, REST API'lerinizi görsel olarak dokümante etmenize ve test etmenize olanak tanır.
  • Springfox kütüphanesi ile Spring Boot uygulamalarınızda Swagger entegrasyonu kolayca yapılabilir.
  • API'lerinizi daha anlaşılır ve açıklayıcı hale getirmek için @Api, @ApiOperation, @ApiParam gibi anotasyonlar kullanabilirsiniz.
  • JWT gibi kimlik doğrulama yöntemlerini Swagger üzerinden test etmek için özelleştirilmiş güvenlik yapılandırması ekebilirsiniz.


9. Swagger Dokümantasyonunu Sadece Belirli Profilde Etkinleştirme


Swagger dokümantasyonunun sadece belirli ortamlarda (örneğin, geliştirme ortamında) etkin olmasını isteyebilirsiniz. Üretim ortamında dokümantasyonun açık olması, güvenlik açısından istenmeyen durumlara yol açabilir. Bu durumu kontrol etmek için @Profile anotasyonunu kullanarak Swagger yapılandırmasını sadece belirli profillerde etkinleştirebilirsiniz.


Örnek: Swagger Dokümantasyonunu Sadece Geliştirme Ortamında Etkinleştirme



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Profile;

import springfox.documentation.builders.PathSelectors;

import springfox.documentation.builders.RequestHandlerSelectors;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spring.web.plugins.Docket;


@Configuration

@Profile("dev")

public class SwaggerConfig {


    @Bean

    public Docket api() {

        return new Docket(DocumentationType.SWAGGER_2)

                .select()

                .apis(RequestHandlerSelectors.any())

                .paths(PathSelectors.any())

                .build();

    }

}



Bu yapılandırma sayesinde Swagger dokümantasyonu yalnızca dev profili etkin olduğunda çalışır. Üretim ortamında Swagger dokümantasyonu otomatik olarak devre dışı bırakılır.


10. Swagger JSON Dokümantasyonu (OpenAPI Spec)


Swagger sadece kullanıcı arayüzü sunmakla kalmaz, aynı zamanda REST API'nizi makine tarafından okunabilir bir formatta (JSON) dokümante eder. Bu format, OpenAPI Specification'a (eski adıyla Swagger Specification) uygun olarak oluşturulur.


Swagger dokümantasyonunun JSON çıktısına şu adresten ulaşabilirsiniz:



http://localhost:8080/v2/api-docs



Bu JSON formatı, API'lerinizi başka araçlarla (örneğin, Postman, Insomnia) entegre etmenizi veya diğer servislerle paylaşmanızı sağlar.


11. Swagger UI ile API'lerinizi Test Etme


Swagger UI arayüzü, API uç noktalarını doğrudan tarayıcı üzerinden test etmenizi sağlar. Aşağıdaki adımları izleyerek Swagger UI kullanarak API'lerinizi test edebilirsiniz:


  1. Swagger UI'ye Erişim: Uygulamanız çalışırken http://localhost:8080/swagger-ui/ adresine gidin.
  2. API'yi İnceleme: Swagger UI, tüm uç noktalarınızı (endpoints) ve bu uç noktaların kabul ettiği parametreleri listeler.
  3. Try it out Butonu ile Test Etme: Her bir uç noktanın yanındaki Try it out butonuna tıklayarak API'nizi test edebilirsiniz. Parametreleri girip "Execute" butonuna basarak doğrudan Swagger üzerinden API çağrısı yapabilirsiniz.
  4. Sonuçları İnceleme: API çağrısının sonucu, yanıt kodu (200, 400, 500 vb.), yanıt mesajı ve dönen veri ile birlikte gösterilir. Bu, API'nizin doğru çalışıp çalışmadığını doğrulamanın kolay bir yoludur.


12. Swagger'ın Avantajları


  • Kolay Dokümantasyon: Swagger, API dokümantasyonu oluşturmayı ve güncellemeyi otomatik hale getirir.
  • Görsel Test Aracı: Swagger UI ile API'lerinizi test etmek için ayrı bir araca ihtiyaç duymazsınız. Tarayıcı üzerinden API'leri deneyebilir ve sonuçları görebilirsiniz.
  • Makine Tarafından Okunabilir Format: Swagger, API dokümantasyonunu JSON formatında sunar, bu sayede diğer sistemlerle kolayca entegre edilebilir.
  • İnteraktif: Swagger UI, API'lerin nasıl çalıştığını görmek ve test etmek için kullanıcı dostu bir arayüz sunar. Bu özellik, geliştiricilerin yanı sıra, teknik olmayan ekiplerin de API'leri anlamasına yardımcı olur.
  • Entegrasyon: Swagger JSON çıktısı sayesinde API'lerinizi Postman veya başka API araçlarına kolayca entegre edebilirsiniz.


13. Swagger ile Gelişmiş Özelleştirmeler


Swagger, API dokümantasyonunu daha kapsamlı hale getirmek için çeşitli özelleştirme seçenekleri sunar. Örneğin, API yollarını (paths) belirli bir yapıya göre filtreleyebilir, model şemalarını (schema) daha ayrıntılı tanımlayabilir veya açıklayıcı bilgiler ekleyebilirsiniz.


Örnek: API Açıklamaları ve Gelişmiş Özelleştirme



import io.swagger.annotations.Api;

import io.swagger.annotations.ApiOperation;

import org.springframework.web.bind.annotation.*;


@RestController

@RequestMapping("/api/orders")

@Api(value = "Order Management System", description = "Operations pertaining to orders in Order Management System")

public class OrderController {


    @GetMapping("/{orderId}")

    @ApiOperation(value = "Get order by ID", response = Order.class)

    public Order getOrderById(@PathVariable String orderId) {

        return new Order(orderId, "Sample Order");

    }


    @PostMapping

    @ApiOperation(value = "Create a new order", response = Order.class)

    public Order createOrder(@RequestBody Order order) {

        return order;

    }

}



Açıklamalar:

  1. @Api: Controller sınıfına genel açıklamalar ekler. value ve description ile API'nin amacını ve fonksiyonunu tanımlayabilirsiniz.
  2. @ApiOperation: Belirli bir endpoint hakkında ayrıntılı bilgi sağlar. value ve response parametreleri ile endpoint'in ne işe yaradığını ve döneceği veri tipini tanımlayabilirsiniz.


14. Swagger Dokümantasyonunu Diğer Servislerle Paylaşma


Swagger JSON çıktısını (OpenAPI Spec) kullanarak diğer servislerle veya ekiplerle API'nizin nasıl kullanılacağını paylaşabilirsiniz. Örneğin, Postman veya Insomnia gibi API test araçlarına Swagger JSON dosyanızı yükleyerek, API'lerinizi hızlıca test edebilir veya diğer ekiplerin API'nizi daha iyi anlamasını sağlayabilirsiniz.


  • Postman Entegrasyonu: Swagger dokümantasyonunu Postman'e aktarmak için, v2/api-docs URL'sinden alınan JSON çıktısını kullanabilirsiniz. Postman'de "Import" seçeneğini kullanarak JSON çıktısını doğrudan yükleyebilir ve tüm API uç noktalarınızı Postman'e ekleyebilirsiniz.


15. Swagger ve OpenAPI


Swagger, son yıllarda OpenAPI Specification (OAS) standardını benimsemiştir. OpenAPI, Swagger'ın önceki versiyonlarıyla aynı mantığı izler, ancak daha standart bir yapı sunar. Spring Boot projelerinde OpenAPI 3.0 kullanarak daha geniş özelliklere ve entegrasyonlara sahip bir API dokümantasyonu oluşturabilirsiniz.


OpenAPI ile Swagger Entegrasyonu


Swagger yerine OpenAPI kullanmak isterseniz, springdoc-openapi kütüphanesini kullanabilirsiniz:



<dependency>

    <groupId>org.springdoc</groupId>

    <artifactId>springdoc-openapi-ui</artifactId>

    <version>1.5.12</version>

</dependency>



OpenAPI ile Swagger arayüzüne şu URL üzerinden erişebilirsiniz:



http://localhost:8080/swagger-ui.html



Özet:

  • Swagger, REST API dokümantasyonunu görsel ve interaktif bir şekilde sunar. Spring Boot projelerinde kolayca entegre edilebilir.
  • Springfox kütüphanesi ile Swagger arayüzü oluşturabilir, API'lerinizi dokümante edebilir ve test edebilirsiniz.
  • JWT veya OAuth gibi kimlik doğrulama yöntemleriyle Swagger arayüzünde API'lerinizi güvenli bir şekilde test edebilirsiniz.
  • Swagger dokümantasyonu sadece geliştirme ortamında etkin olacak şekilde profillere göre yapılandırılabilir.
  • OpenAPI standardı ile daha geniş özelliklere sahip bir API dokümantasyonu sunulabilir.


Swagger, özellikle büyük ölçekli projelerde ve ekip çalışmasında API'lerin anlaşılmasını, geliştirilmesini ve test edilmesini kolaylaştırır.

21. Spring Boot Scheduler Kullanımı

21. Spring Boot Scheduler Kullanımı


Spring Boot, zamanlanmış görevler (scheduled tasks) oluşturmayı ve yönetmeyi kolaylaştıran bir mekanizma sunar. @Scheduled anotasyonu ile belirli bir zaman aralığında veya belirli bir zamana göre görevler (tasks) çalıştırılabilir. Bu, örneğin belirli aralıklarla veri temizleme, veri senkronizasyonu gibi otomatik işlemleri gerçekleştirmek için kullanılır.


Spring Boot Scheduler'ı etkinleştirmek için @EnableScheduling anotasyonunu kullanmanız gerekmektedir.


1. Zamanlanmış Görevleri Etkinleştirme


Zamanlanmış görevlerin çalışması için @EnableScheduling anotasyonunu eklemeniz gerekir. Bu anotasyonu uygulamanın ana sınıfına veya bir yapılandırma sınıfına ekleyebilirsiniz.


Örnek: Scheduler'ı Etkinleştirme



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.scheduling.annotation.EnableScheduling;


@SpringBootApplication

@EnableScheduling

public class SchedulerApplication {


    public static void main(String[] args) {

        SpringApplication.run(SchedulerApplication.class, args);

    }

}



2. @Scheduled Anotasyonu ile Zamanlanmış Görevler


@Scheduled anotasyonu ile zamanlanmış görevler oluşturulabilir. Bu anotasyon farklı zamanlama seçenekleri ile görevlerin ne zaman çalışacağını belirlemenize olanak tanır.


Örnek: Sabit Aralıklarla Görev Çalıştırma


fixedRate parametresi, bir önceki görev tamamlanmış olsun veya olmasın, belirli bir sabit aralıkla görevin çalışmasını sağlar.



import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;


@Component

public class ScheduledTasks {


    @Scheduled(fixedRate = 5000)

    public void scheduledTask() {

        System.out.println("Scheduled task running every 5 seconds");

    }

}



Bu örnekte, scheduledTask() metodu her 5 saniyede bir çalıştırılacaktır.


Diğer @Scheduled Parametreleri:

  • fixedRate: Görev sabit bir hızda çalıştırılır. Bir önceki çalıştırmanın bitmesi beklenmez, her fixedRate'te görev başlatılır.
  • fixedDelay: Bir önceki çalıştırmanın bitiminden itibaren belirli bir süre sonra görev başlatılır.
  • initialDelay: İlk görevin başlatılması için gecikme süresi belirler.
  • cron: Cron ifadesi kullanarak görevlerin belirli zamanlarda çalıştırılmasını sağlar.


3. Fixed Delay ile Zamanlanmış Görevler


fixedDelay parametresi, bir önceki görev tamamlandıktan sonra belirli bir gecikme süresi ile yeni görevin başlatılmasını sağlar.



import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;


@Component

public class ScheduledTasks {


    @Scheduled(fixedDelay = 5000)

    public void scheduledTaskWithFixedDelay() {

        System.out.println("Scheduled task with fixed delay (5 seconds) running after previous task completes");

    }

}



Bu örnekte, görev tamamlandıktan sonra 5 saniye beklenir ve ardından yeni görev başlatılır.


4. Initial Delay ile Zamanlanmış Görevler


initialDelay parametresi, uygulama başlatıldıktan sonra ilk görevin başlatılması için bir gecikme süresi ayarlar.



import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;


@Component

public class ScheduledTasks {


    @Scheduled(fixedRate = 5000, initialDelay = 10000)

    public void scheduledTaskWithInitialDelay() {

        System.out.println("Scheduled task running every 5 seconds after an initial delay of 10 seconds");

    }

}



Bu örnekte, uygulama başlatıldıktan 10 saniye sonra görev çalışmaya başlar ve ardından her 5 saniyede bir çalışmaya devam eder.


5. Cron İfadesi ile Zamanlama


Cron ifadesi, zamanlanmış görevlerin belirli bir takvime göre çalıştırılmasını sağlar. Cron formatı saniye, dakika, saat, gün, ay ve hafta günü gibi zaman birimlerini kullanarak esnek zamanlama sağlar.


Örnek: Cron İfadesi ile Görev Zamanlama



import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;


@Component

public class ScheduledTasks {


    // Her gün sabah 9:00'da çalışacak bir cron görevi

    @Scheduled(cron = "0 0 9 * * ?")

    public void scheduledTaskWithCronExpression() {

        System.out.println("Scheduled task running at 9:00 AM every day");

    }

}



Cron Formatı:

  • Saniye (0 - 59)
  • Dakika (0 - 59)
  • Saat (0 - 23)
  • Ayın Günü (1 - 31)
  • Ay (1 - 12 veya JAN-DEC)
  • Haftanın Günü (0 - 7 veya SUN-SAT, 0 ve 7 Pazar'ı temsil eder)


Örnek cron ifadeleri:

  • "0 0 * * * *": Her saat başında.
  • "0 0 9 * * *": Her gün sabah 9:00'da.
  • "0 0 9,12,15 * * *": Her gün 9:00, 12:00 ve 15:00'te.


6. Zamanlanmış Görevlerin Konfigürasyonu


application.properties dosyasında zamanlanmış görevler için çeşitli ayarlar yapabilirsiniz. Örneğin, zamanlanmış görevlerin varsayılan olarak çalışıp çalışmayacağını kontrol edebilirsiniz.


Örnek: Zamanlanmış Görevleri Devre Dışı Bırakma


Zamanlanmış görevleri devre dışı bırakmak için application.properties dosyasına şu ayarı ekleyebilirsiniz:



spring.task.scheduling.enabled=false



Bu ayar, zamanlanmış görevlerin çalışmasını devre dışı bırakır.


7. Asenkron Görevler ile Kullanım


Eğer zamanlanmış görevlerin asenkron olarak çalışmasını istiyorsanız, @Async anotasyonunu kullanabilirsiniz. Bu, görevlerin ayrı bir thread'de çalışmasını sağlar.


Örnek: Zamanlanmış Asenkron Görev



import org.springframework.scheduling.annotation.Async;

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;


@Component

public class AsyncScheduledTasks {


    @Async

    @Scheduled(fixedRate = 5000)

    public void scheduledTaskWithAsync() {

        System.out.println("Asynchronous scheduled task running every 5 seconds");

    }

}



8. Zamanlanmış Görevlerin İzlenmesi


Zamanlanmış görevlerin ne zaman çalıştığını ve ne kadar sürdüğünü izlemek için Spring Boot Actuator'ı kullanabilirsiniz. Spring Boot Actuator, zamanlanmış görevlerin metriklerini toplar ve bunları izleyebilirsiniz.


Zamanlanmış Görev Metriklerini Görüntüleme:

Eğer Actuator etkinleştirilmişse, zamanlanmış görevlerin performansını şu uç noktada izleyebilirsiniz:



http://localhost:8080/actuator/metrics



Bu uç nokta, uygulamanızdaki zamanlanmış görevlerin çalışma süresi ve sıklığı gibi metrikleri görüntülemenizi sağlar.


Özet:

  • Spring Boot Scheduler ile zamanlanmış görevler kolayca tanımlanabilir.
  • @Scheduled anotasyonu ile sabit aralıklarla, sabit gecikme süreleriyle veya cron ifadeleriyle görevler zamanlanabilir.
  • Zamanlanmış görevlerin asenkron olarak çalışmasını sağlamak için @Async anotasyonu kullanılabilir.
  • Zamanlanmış görevlerin izlenmesi ve yönetilmesi için Spring Boot Actuator entegre edilebilir.

  

Bu özellikler sayesinde Spring Boot uygulamalarında otomatik olarak belirli işlemleri belirli zamanlarda veya periyotlarda gerçekleştirmek oldukça kolay ve etkilidir.


22. Asenkron İşlemler

  • @Async anotasyonunu kullanarak asenkron işlemler yapın.
  • 22. Asenkron İşlemler


Spring Boot, asenkron işlemleri kolayca yönetebilmek için @Async anotasyonunu sağlar. Bu anotasyon ile işlerinizi farklı bir thread'de çalıştırarak ana iş akışını engellemeden daha hızlı ve verimli işlemler yapabilirsiniz. Asenkron işlemler özellikle uzun süreli çalışan görevlerde kullanışlıdır; örneğin dosya işlemleri, e-posta gönderimi, veri analizleri gibi görevleri asenkron hale getirerek performansı artırabilirsiniz.


1. @Async Anotasyonunun Kullanımı


Spring Boot uygulamanızda asenkron işlemleri etkinleştirmek için aşağıdaki adımları izleyebilirsiniz.


Adım 1: @EnableAsync ile Asenkron İşlemleri Etkinleştirme


Spring Boot'ta asenkron işlemleri kullanabilmek için uygulamanızın ana sınıfında veya bir yapılandırma sınıfında @EnableAsync anotasyonunu kullanarak asenkron desteği etkinleştirmeniz gerekir.



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.scheduling.annotation.EnableAsync;


@SpringBootApplication

@EnableAsync

public class AsyncApplication {


    public static void main(String[] args) {

        SpringApplication.run(AsyncApplication.class, args);

    }

}



Adım 2: @Async ile Asenkron Metot Tanımlama


@Async anotasyonu ile asenkron işlemler tanımlayabilirsiniz. Bu metotlar farklı bir thread'de çalıştırılır.


Örnek: Basit Asenkron İşlem



import org.springframework.scheduling.annotation.Async;

import org.springframework.stereotype.Service;


@Service

public class AsyncService {


    @Async

    public void asyncMethod() {

        System.out.println("Async method started on thread: " + Thread.currentThread().getName());

        try {

            Thread.sleep(5000); // 5 saniye bekleyerek uzun süren bir işlem simüle ediliyor

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        System.out.println("Async method finished");

    }

}



Bu örnekte asyncMethod() adlı metot, 5 saniyelik bir gecikme ile asenkron olarak çalıştırılacaktır. Metot çalıştırıldığında ana iş akışı bu işlem için beklemeyecektir.


Adım 3: Asenkron Metodu Çağırma


Bir controller veya başka bir service sınıfı içerisinde asenkron metodu çağırabilirsiniz.


Örnek: Controller Sınıfı ile Asenkron Metot Çağrısı



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class AsyncController {


    @Autowired

    private AsyncService asyncService;


    @GetMapping("/run-async")

    public String runAsyncMethod() {

        System.out.println("Controller method called on thread: " + Thread.currentThread().getName());

        asyncService.asyncMethod(); // Asenkron metot çağrısı

        return "Async method has been triggered!";

    }

}



Bu örnekte /run-async endpoint'i çağrıldığında, asenkron metot başka bir thread'de çalıştırılır ve ana iş akışı bloklanmadan devam eder.


2. Asenkron İşlemlerle Geri Dönüş Tipleri


Asenkron işlemler genellikle void döner; ancak, bir işlem sonucunu geri döndürmek isterseniz CompletableFuture kullanabilirsiniz. CompletableFuture ile asenkron işlem tamamlandığında bir sonuç döndürülebilir.


Örnek: CompletableFuture ile Sonuç Döndürme



import org.springframework.scheduling.annotation.Async;

import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;


@Service

public class AsyncService {


    @Async

    public CompletableFuture<String> asyncMethodWithReturn() {

        System.out.println("Async method with return started on thread: " + Thread.currentThread().getName());

        try {

            Thread.sleep(3000); // Uzun süren bir işlem

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        System.out.println("Async method with return finished");

        return CompletableFuture.completedFuture("Task Completed");

    }

}



CompletableFuture Kullanımı Controller'da



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;


import java.util.concurrent.CompletableFuture;


@RestController

public class AsyncController {


    @Autowired

    private AsyncService asyncService;


    @GetMapping("/run-async-with-return")

    public CompletableFuture<String> runAsyncMethodWithReturn() {

        return asyncService.asyncMethodWithReturn(); // CompletableFuture döner

    }

}



Bu örnekte, /run-async-with-return endpoint'i çağrıldığında, asenkron işlem başladıktan sonra CompletableFuture kullanarak işlemin sonucunu döner. Bu, asenkron işlemlerde bir geri dönüş değeri olduğunda kullanışlıdır.


3. Asenkron İşlemlerin Zamanlanması


Asenkron metotları zamanlanmış görevlerle birleştirerek belirli aralıklarla çalışan asenkron işlemler oluşturabilirsiniz. Bunun için @Scheduled ve @Async anotasyonlarını birlikte kullanabilirsiniz.


Örnek: Zamanlanmış Asenkron İşlem



import org.springframework.scheduling.annotation.Async;

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Service;


@Service

public class ScheduledAsyncService {


    @Async

    @Scheduled(fixedRate = 5000)

    public void scheduledAsyncTask() {

        System.out.println("Asynchronous scheduled task started on thread: " + Thread.currentThread().getName());

    }

}



Bu örnekte, scheduledAsyncTask() metodu her 5 saniyede bir asenkron olarak farklı bir thread'de çalıştırılacaktır.


4. Asenkron İşlemler İçin Executor Yapılandırması


Spring Boot, asenkron işlemleri varsayılan bir thread pool kullanarak çalıştırır. Ancak, kendi özelleştirilmiş Executor yapınızı tanımlayarak thread havuzunu kontrol edebilirsiniz. Bunun için, bir ThreadPoolTaskExecutor yapılandırması oluşturabilirsiniz.


Örnek: Özelleştirilmiş Executor Tanımlama



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.scheduling.annotation.AsyncConfigurer;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;


import java.util.concurrent.Executor;


@Configuration

public class AsyncConfig implements AsyncConfigurer {


    @Bean(name = "taskExecutor")

    public Executor taskExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setCorePoolSize(5);

        executor.setMaxPoolSize(10);

        executor.setQueueCapacity(100);

        executor.setThreadNamePrefix("AsyncThread-");

        executor.initialize();

        return executor;

    }

}



Bu örnekte:

  • CorePoolSize: Minimum thread sayısıdır.
  • MaxPoolSize: Maksimum thread sayısıdır.
  • QueueCapacity: Bekleyen işlerin kuyruğu için kapasite belirler.


Bu yapılandırma ile asenkron işlemler bu thread pool içinde çalışacaktır. Her asenkron işlem AsyncThread- ile başlayan thread adları ile çalıştırılacaktır.


5. Asenkron İşlemlerin Hata Yönetimi


Asenkron işlemler sırasında meydana gelen hataları yönetmek için AsyncUncaughtExceptionHandler kullanabilirsiniz. Bu, asenkron işlemlerde fırlatılan istisnaları yakalamak için bir yöntemdir.


Örnek: Asenkron Hata Yönetimi



import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;

import org.springframework.context.annotation.Configuration;

import org.springframework.scheduling.annotation.AsyncConfigurer;


import java.lang.reflect.Method;


@Configuration

public class AsyncConfig implements AsyncConfigurer {


    @Override

    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

        return new CustomAsyncExceptionHandler();

    }

}


class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {


    @Override

    public void handleUncaughtException(Throwable ex, Method method, Object... params) {

        System.out.println("Exception message - " + ex.getMessage());

        System.out.println("Method name - " + method.getName());

    }

}



Bu örnekte, asenkron bir işlem sırasında meydana gelen hatalar CustomAsyncExceptionHandler tarafından yakalanacak ve yönetilecektir.


Özet:

  • @Async anotasyonu ile Spring Boot uygulamalarında asenkron işlemler tanımlayabilirsiniz.
  • Asenkron işlemler farklı bir thread'de çalışarak ana iş akışını kesintiye uğratmaz ve performansı artırır.
  • CompletableFuture kullanarak asenkron işlemlerden sonuç döndürebilirsiniz.
  • Asenkron işlemler için özelleştirilmiş thread pool yapılandırabilir ve işlemleri daha iyi yönetebilirsiniz.
  • Hata yönetimi için AsyncUncaughtExceptionHandler kullanarak asenkron işlemlerdeki istisnaları yakalayabilirsiniz.


Bu yöntemler ile uygulamanızda asenkron işlemleri verimli bir şekilde kullan


23. Email Gönderimi

  • Spring Boot ile email gönderimi yapın.

23. Spring Boot ile E-posta Gönderimi


Spring Boot, e-posta gönderimi işlemlerini kolayca yapabilmeniz için Spring Mail desteği sunar. Spring Boot’ta e-posta gönderimi yapmak için JavaMailSender sınıfını kullanabilirsiniz. JavaMailSender SMTP üzerinden e-posta göndermek için kullanılır ve e-posta sunucusu ayarlarını yapılandırarak e-posta işlemlerini yönetebilirsiniz.


Aşağıda adım adım Spring Boot ile e-posta gönderimi nasıl yapılır, açıklıyorum.


1. Gerekli Bağımlılıkları Ekleyin


İlk olarak, Spring Boot Starter Mail bağımlılığını projenize eklemeniz gerekir. Bu bağımlılık, e-posta gönderimi için gerekli tüm kütüphaneleri sağlar.


pom.xml Bağımlılığı:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-mail</artifactId>

</dependency>



Bu bağımlılığı ekledikten sonra Spring Boot, JavaMailSender bileşenini otomatik olarak uygulamaya entegre eder.


2. E-posta Sunucusu Yapılandırması


E-posta göndermek için SMTP ayarlarını application.properties dosyasında tanımlamanız gerekir. Genellikle, Gmail gibi yaygın kullanılan SMTP sunucuları için yapılandırmalar şu şekildedir:


application.properties Dosyası:



spring.mail.host=smtp.gmail.com

spring.mail.port=587

spring.mail.username=your-email@gmail.com

spring.mail.password=your-email-password

spring.mail.properties.mail.smtp.auth=true

spring.mail.properties.mail.smtp.starttls.enable=true



  • spring.mail.host: E-posta sağlayıcınızın SMTP sunucusu (Gmail için smtp.gmail.com).
  • spring.mail.port: SMTP portu (Gmail için 587).
  • spring.mail.username: E-posta göndermek için kullanacağınız e-posta adresi.
  • spring.mail.password: E-posta adresinizin şifresi (Güvenlik nedeniyle şifrelerin çevresel değişkenlerden ya da daha güvenli yollarla yönetilmesi önerilir).
  • spring.mail.properties.mail.smtp.auth: SMTP sunucusunun kimlik doğrulamasını etkinleştirir.
  • spring.mail.properties.mail.smtp.starttls.enable: TLS güvenlik katmanını etkinleştirir (Gmail için gereklidir).


3. E-posta Göndermek İçin Servis Sınıfı


E-posta göndermek için bir servis sınıfı oluşturup, JavaMailSender bileşenini kullanarak e-posta gönderebilirsiniz.


Örnek: Basit E-posta Gönderimi



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.mail.SimpleMailMessage;

import org.springframework.mail.javamail.JavaMailSender;

import org.springframework.stereotype.Service;


@Service

public class EmailService {


    @Autowired

    private JavaMailSender mailSender;


    public void sendEmail(String to, String subject, String text) {

        SimpleMailMessage message = new SimpleMailMessage();

        message.setTo(to); // Alıcı e-posta adresi

        message.setSubject(subject); // E-posta konusu

        message.setText(text); // E-posta metni


        mailSender.send(message); // E-postayı gönderir

        System.out.println("E-posta başarıyla gönderildi!");

    }

}



Açıklamalar:

  • SimpleMailMessage: Basit düz metin e-posta göndermek için kullanılır.
  • setTo(): E-posta alıcısını belirtir.
  • setSubject(): E-posta konusunu belirtir.
  • setText(): E-posta içeriğini belirtir.
  • mailSender.send(): E-postayı gönderir.


4. E-posta Gönderimini Çağırma


Oluşturduğunuz EmailService sınıfını bir controller veya başka bir servis sınıfı içinde kullanarak e-posta gönderebilirsiniz.


Örnek: E-posta Gönderimi İçin Controller



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class EmailController {


    @Autowired

    private EmailService emailService;


    @GetMapping("/send-email")

    public String sendEmail(

            @RequestParam String to,

            @RequestParam String subject,

            @RequestParam String text) {


        emailService.sendEmail(to, subject, text);

        return "E-posta başarıyla gönderildi!";

    }

}



Bu örnekte /send-email endpoint'ine GET isteği yaparak e-posta gönderimini tetikleyebilirsiniz. Örneğin:



http://localhost:8080/send-email?to=example@example.com&subject=Test&text=This is a test email



Bu URL'e bir istek yapıldığında, belirtilen adrese belirtilen konu ve içerikle bir e-posta gönderilecektir.


5. HTML Formatında E-posta Gönderimi


Eğer e-postanızın HTML formatında olmasını istiyorsanız, MimeMessage kullanarak HTML formatında e-posta gönderebilirsiniz.


Örnek: HTML Formatında E-posta Gönderimi



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.mail.javamail.JavaMailSender;

import org.springframework.mail.javamail.MimeMessageHelper;

import org.springframework.stereotype.Service;


import javax.mail.MessagingException;

import javax.mail.internet.MimeMessage;


@Service

public class HtmlEmailService {


    @Autowired

    private JavaMailSender mailSender;


    public void sendHtmlEmail(String to, String subject, String htmlBody) throws MessagingException {

        MimeMessage message = mailSender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(message, true);


        helper.setTo(to);

        helper.setSubject(subject);

        helper.setText(htmlBody, true); // HTML formatında içerik gönderilir


        mailSender.send(message);

        System.out.println("HTML formatında e-posta başarıyla gönderildi!");

    }

}



Bu örnekte, MimeMessageHelper kullanılarak HTML formatında e-posta gönderimi yapılır. setText() metodundaki ikinci parametre true yapılarak HTML içeriği desteklenir.


6. E-posta Gönderimi İçin Yaygın Hatalar ve Çözümleri


Gmail İle E-posta Gönderiminde Hatalar:

  • Gmail'de Az Güvenli Uygulamalar: Gmail’in az güvenli uygulamaları engellediği durumlarda e-posta gönderimi başarısız olabilir. Gmail ayarlarında "Less secure apps" ayarını etkinleştirmeniz gerekebilir. Ancak, bu durum güvenlik açıklarına yol açabilir, bu yüzden güvenli yöntemler tercih edilmelidir.
  • Uygulama Şifresi: İki aşamalı doğrulama etkinse, normal Gmail şifresi yerine uygulama şifresi kullanmanız gerekebilir.


TLS veya SSL Hataları:

  • Eğer TLS veya SSL ayarları yanlış yapılandırılmışsa bağlantı hatası alabilirsiniz. spring.mail.properties.mail.smtp.starttls.enable=true ve spring.mail.properties.mail.smtp.ssl.trust=smtp.gmail.com gibi ayarlar ekleyerek bu hataları çözebilirsiniz.


7. Email Gönderiminde İleri Seviye Özellikler


  • Ek Dosya Gönderimi: MimeMessageHelper ile e-postaya ek dosyalar (attachment) ekleyebilirsiniz.
  • CC ve BCC Kullanımı: setCc() ve setBcc() metotları ile e-posta kopyaları ve gizli kopyalar gönderebilirsiniz.


Örnek: Ek Dosya Gönderimi



import org.springframework.mail.javamail.MimeMessageHelper;

import org.springframework.stereotype.Service;


import javax.mail.MessagingException;

import javax.mail.internet.MimeMessage;

import java.io.File;


@Service

public class AttachmentEmailService {


    @Autowired

    private JavaMailSender mailSender;


    public void sendEmailWithAttachment(String to, String subject, String text, File attachment) throws MessagingException {

        MimeMessage message = mailSender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(message, true);


        helper.setTo(to);

        helper.setSubject(subject);

        helper.setText(text);

        helper.addAttachment("Attachment", attachment); // Ek dosya eklenir


        mailSender.send(message);

        System.out.println("E-posta ek ile gönderildi!");

    }

}



Özet:

  • Spring Boot ile e-posta gönderimi yapmak için JavaMailSender kullanabilirsiniz.
  • E-posta yapılandırmasını application.properties dosyasında SMTP ayarlarını tanımlayarak yapabilirsiniz.
  • SimpleMailMessage ile basit metin tabanlı e-postalar gönderebilir, MimeMessage ile HTML formatında veya ek dosyalı e-postalar gönderebilirsiniz.
  • Daha güvenli bir e-posta yapılandırması için SMTP yapılandırmalarınızı dikkatlice yönetmeli ve mümkünse çevresel değişkenler (environment variables) kullanarak e-posta şifrenizi güvenli bir şekilde saklamalısınız. Bu yöntem, şifrelerin kaynak kodunda görünür olmasını engeller.


8. SMTP Ayarlarının Güvenli Yönetimi


E-posta gönderimi için kullanılan kullanıcı adı, şifre gibi hassas bilgilerin kaynak kodunda saklanması güvenlik açısından risklidir. Bunun yerine, bu bilgileri çevresel değişkenlerle ya da güvenli yapılandırma yönetimi sistemleri ile yönetebilirsiniz.


Örnek: Şifreyi Çevresel Değişkenlerden Alma


application.properties dosyanızda kullanıcı adı ve şifreyi çevresel değişkenler ile kullanabilirsiniz:



spring.mail.username=${EMAIL_USERNAME}

spring.mail.password=${EMAIL_PASSWORD}



Daha sonra, bu çevresel değişkenleri çalıştırma ortamınıza ekleyerek şifreyi güvenli bir şekilde saklayabilirsiniz:



export EMAIL_USERNAME=your-email@gmail.com

export EMAIL_PASSWORD=your-secure-password



Bu yöntem, özellikle üretim ortamlarında hassas bilgilerin güvenli bir şekilde yönetilmesini sağlar.


9. Email Gönderimi İçin Test ve Loglama


E-posta gönderim işlemlerini doğru bir şekilde test etmek önemlidir. E-posta sunucusuyla ilgili bir hata oluştuğunda, e-posta gönderimi başarısız olabilir ve bu tür hataları yakalamak, loglarda görmek önemlidir. Ayrıca, üretim ortamında doğrudan e-posta gönderimi yerine, geliştirme ve test ortamlarında sahte bir SMTP sunucusu kullanarak e-posta işlemlerini test edebilirsiniz.


Fake SMTP Sunucusu ile Test


application.properties dosyanızda spring.mail.test-connection=true ayarını kullanarak e-posta sunucusu bağlantınızı test edebilirsiniz:



spring.mail.test-connection=true



Bu sayede e-posta gönderme işlemlerini bir geliştirme ortamında test edebilirsiniz. Gerçek e-posta gönderimi yapmadan e-posta gönderim hatalarını kontrol edebilirsiniz.


10. Email Gönderiminde Kullanıcı Bilgilendirme


E-posta gönderimi, kullanıcıya işlem hakkında bilgi vermek için kullanılabilir. Örneğin, kullanıcı kaydı, şifre sıfırlama veya sipariş onayları gibi işlemler sonrasında e-posta ile bilgilendirme yapılabilir. Bu durumda, e-postanın başarılı bir şekilde gönderildiğinden emin olmalı ve hata durumunda kullanıcıyı bilgilendirmelisiniz.


Örnek: Hata Yönetimi ile Email Gönderimi



import org.springframework.mail.SimpleMailMessage;

import org.springframework.mail.javamail.JavaMailSender;

import org.springframework.stereotype.Service;


@Service

public class EmailService {


    @Autowired

    private JavaMailSender mailSender;


    public String sendEmail(String to, String subject, String text) {

        try {

            SimpleMailMessage message = new SimpleMailMessage();

            message.setTo(to);

            message.setSubject(subject);

            message.setText(text);


            mailSender.send(message);  // E-posta gönderme işlemi

            return "E-posta başarıyla gönderildi!";

        } catch (Exception e) {

            return "E-posta gönderimi sırasında hata oluştu: " + e.getMessage();

        }

    }

}



Bu örnekte, e-posta gönderimi sırasında bir hata oluşursa, kullanıcıya hatayla ilgili bilgi döndürülür. Bu yöntem, e-posta sunucusunun doğru çalışmadığı durumlarda kullanıcıya geri bildirim sağlar.


11. Toplu Email Gönderimi


Spring Boot ile birden fazla kullanıcıya toplu e-posta gönderimi yapmak oldukça kolaydır. SimpleMailMessage sınıfında setTo() metoduna birden fazla e-posta adresi ekleyerek bu işlemi gerçekleştirebilirsiniz.


Örnek: Toplu Email Gönderimi



import org.springframework.mail.SimpleMailMessage;

import org.springframework.mail.javamail.JavaMailSender;

import org.springframework.stereotype.Service;


@Service

public class BulkEmailService {


    @Autowired

    private JavaMailSender mailSender;


    public void sendBulkEmail(String[] recipients, String subject, String text) {

        SimpleMailMessage message = new SimpleMailMessage();

        message.setTo(recipients); // Birden fazla alıcı

        message.setSubject(subject);

        message.setText(text);


        mailSender.send(message);

        System.out.println("Toplu e-posta başarıyla gönderildi!");

    }

}



Bu örnekte, setTo() metoduna bir dizi (array) e-posta adresi geçirilir ve e-posta mesajı bu alıcılara topluca gönderilir. Bu yöntemle, bir etkinlik veya kampanya için birden fazla kişiye aynı anda e-posta gönderebilirsiniz.


12. Asenkron Email Gönderimi


E-posta gönderme işlemi zaman alabilir ve bu işlemi asenkron hale getirerek ana iş akışını engellemeden e-posta gönderebilirsiniz. Spring Boot’ta @Async anotasyonu kullanarak e-posta gönderimini asenkron hale getirebilirsiniz.


Örnek: Asenkron Email Gönderimi



import org.springframework.mail.SimpleMailMessage;

import org.springframework.mail.javamail.JavaMailSender;

import org.springframework.scheduling.annotation.Async;

import org.springframework.stereotype.Service;


@Service

public class AsyncEmailService {


    @Autowired

    private JavaMailSender mailSender;


    @Async

    public void sendEmailAsync(String to, String subject, String text) {

        SimpleMailMessage message = new SimpleMailMessage();

        message.setTo(to);

        message.setSubject(subject);

        message.setText(text);


        mailSender.send(message);

        System.out.println("Asenkron e-posta gönderildi!");

    }

}



Bu örnekte @Async anotasyonu ile e-posta gönderme işlemi asenkron hale getirilmiştir. Bu sayede ana iş akışı bloklanmadan e-posta gönderimi gerçekleşir. Asenkron e-posta gönderimi için @EnableAsync anotasyonunun uygulama giriş noktasına eklenmesi gerektiğini unutmayın.


Özet:


  • Spring Boot ile JavaMailSender kullanarak e-posta gönderimi kolayca yapılabilir.
  • E-posta sunucusu ayarları (SMTP, port, kullanıcı adı ve şifre) application.properties dosyasında tanımlanır.
  • Basit metin e-postalar için SimpleMailMessage, HTML formatında veya ek dosyalı e-postalar için MimeMessage kullanılabilir.
  • Asenkron e-posta gönderimi için @Async anotasyonu kullanılabilir.
  • E-posta gönderiminde hata yönetimi ve güvenli yapılandırma (örn. çevresel değişkenler ile şifre yönetimi) dikkat edilmesi gereken önemli konulardır.


Spring Boot ile e-posta gönderimi, uygulamanızda kullanıcı iletişimini sağlamak için güçlü ve esnek bir çözüm sunar.

24. Profil Resimlerinin Upload Edilmesi

  • Multipart dosyaları yüklemek için Spring Boot'u kullanın.
  • 24. Profil Resimlerinin Upload Edilmesi


Spring Boot, MultipartFile kullanarak dosya yükleme işlemlerini kolaylaştırır. Özellikle profil resimleri gibi kullanıcıya özgü dosyaların sunucuya yüklenmesi ve saklanması yaygın bir senaryodur. Spring Boot, MultipartFile desteği ile dosya yükleme işlemlerini sorunsuz bir şekilde yönetmenizi sağlar.


1. Multipart Dosya Yükleme İçin Gerekli Ayarlar


Spring Boot projelerinde dosya yükleme işlemlerini etkinleştirmek için bazı ayarlamaların yapılması gerekmektedir.


application.properties Dosyası Ayarları:



# Multipart dosya yükleme özelliklerini etkinleştirin

spring.servlet.multipart.enabled=true

spring.servlet.multipart.max-file-size=2MB   # Maksimum dosya boyutu

spring.servlet.multipart.max-request-size=2MB  # Maksimum istek boyutu



Bu ayarlarla, yüklenebilecek dosyaların maksimum boyutunu tanımlayabilirsiniz. Örneğin, maksimum 2MB'lik dosyaların yüklenmesine izin verilmiştir.


2. MultipartFile ile Profil Resmi Yükleme


MultipartFile sınıfı, dosyaların yüklenmesini yönetmek için kullanılan bir sınıftır. Aşağıda bir profil resminin nasıl yükleneceğini adım adım gösteriyorum.


Adım 1: Profil Resmi Yükleme için Controller Sınıfı



import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;

import org.springframework.http.ResponseEntity;


import java.io.File;

import java.io.IOException;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;


@RestController

@RequestMapping("/api/profile")

public class ProfileController {


    // Dosyanın kaydedileceği dizin

    private static final String UPLOAD_DIR = "uploads/";


    @PostMapping("/upload")

    public ResponseEntity<String> uploadProfilePicture(@RequestParam("file") MultipartFile file) {

        if (file.isEmpty()) {

            return ResponseEntity.badRequest().body("Dosya yüklenemedi. Boş dosya seçildi.");

        }


        try {

            // Yüklenen dosyayı kaydetme işlemi

            byte[] bytes = file.getBytes();

            Path path = Paths.get(UPLOAD_DIR + file.getOriginalFilename());

            Files.write(path, bytes);


            return ResponseEntity.ok("Dosya başarıyla yüklendi: " + file.getOriginalFilename());

        } catch (IOException e) {

            return ResponseEntity.status(500).body("Dosya yükleme hatası: " + e.getMessage());

        }

    }

}



Açıklamalar:

  • MultipartFile: Dosyanın sunucuya yüklenmesi için kullanılır.
  • file.getBytes(): Yüklenen dosyayı byte dizisine çevirir.
  • Files.write(): Dosyayı belirttiğiniz dizine kaydeder.
  • file.getOriginalFilename(): Yüklenen dosyanın orijinal adını alır.
  • UPLOAD_DIR: Dosyanın kaydedileceği dizin.


Adım 2: Upload Dizini Oluşturma


Yüklenen dosyaların kaydedileceği dizin olan uploads/ klasörünü projenizin kök dizininde oluşturun. Eğer bu dizin mevcut değilse, uygulama çalışırken otomatik olarak oluşturabilirsiniz.


3. Dosya Yükleme İşlemini Test Etme


Yukarıdaki kodu kullanarak eğer uygulamanız çalışıyorsa, Postman veya tarayıcı tabanlı bir araçla dosya yükleme işlemini test edebilirsiniz. Örneğin, Postman ile aşağıdaki ayarlarla bir POST isteği gönderebilirsiniz:


  • URL: http://localhost:8080/api/profile/upload
  • Method: POST
  • Body: form-data seçin ve dosya yüklemek için bir alan oluşturun (örneğin file olarak adlandırın).


4. Yüklenen Dosyayı Geri Döndürme


Yüklenen dosyayı kullanıcının görüntüleyebilmesi için bir endpoint oluşturarak dosyanın URL'sini döndürebilirsiniz.


Adım 3: Yüklenen Profil Resmini Geri Döndürme



import org.springframework.core.io.Resource;

import org.springframework.core.io.UrlResource;

import org.springframework.http.HttpHeaders;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


import java.nio.file.Path;

import java.nio.file.Paths;


@RestController

@RequestMapping("/api/profile")

public class ProfileController {


    private static final String UPLOAD_DIR = "uploads/";


    // Yüklenen dosyayı geri döndürme

    @GetMapping("/picture/{filename}")

    public ResponseEntity<Resource> getProfilePicture(@PathVariable String filename) {

        try {

            Path filePath = Paths.get(UPLOAD_DIR + filename);

            Resource resource = new UrlResource(filePath.toUri());


            if (!resource.exists()) {

                return ResponseEntity.notFound().build();

            }


            return ResponseEntity.ok()

                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")

                    .body(resource);

        } catch (Exception e) {

            return ResponseEntity.status(500).body(null);

        }

    }

}



Bu örnek, yüklenen dosyanın geri döndürülmesini sağlar. Kullanıcı, http://localhost:8080/api/profile/picture/your-filename.jpg adresinden profil resmini alabilir.


Açıklamalar:

  • UrlResource: Dosyanın URL'sini kullanarak dosya kaynağını döndürür.
  • HttpHeaders.CONTENT_DISPOSITION: Dosyanın indirilmesi için gerekli olan başlığı ekler.


5. Profil Resmi Yükleme İçin İleri Seviye Özellikler


a. Dosya Formatı ve Boyutu Kontrolü


Dosya formatlarını ve boyutunu kontrol etmek, yalnızca belirli türdeki dosyaların (örneğin, .jpg, .png) yüklenmesini sağlamak için önemlidir.



if (!file.getContentType().equals("image/jpeg") && !file.getContentType().equals("image/png")) {

    return ResponseEntity.badRequest().body("Yalnızca JPG veya PNG dosyalarına izin verilir.");

}


if (file.getSize() > 2_000_000) {

    return ResponseEntity.badRequest().body("Dosya boyutu 2MB'ı geçemez.");

}



Bu şekilde dosya formatını ve boyutunu kontrol edebilirsiniz.


b. Yüklenen Dosyanın Adını Değiştirme


Yüklenen dosyanın adını değiştirmek (örneğin, benzersiz bir ad oluşturmak) dosya adlarının çakışmasını önleyebilir:



String uniqueFilename = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();

Path path = Paths.get(UPLOAD_DIR + uniqueFilename);

Files.write(path, file.getBytes());



Bu, dosyanın adını benzersiz bir UUID ile değiştirir ve dosyaların çakışmasını engeller.


c. Dosya Yolu ve URL Geri Döndürme


Yüklenen dosyanın sunucuda nerede saklandığını geri döndürebilir ve bu URL'yi kullanıcıya gösterebilirsiniz.



String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()

    .path("/api/profile/picture/")

    .path(file.getOriginalFilename())

    .toUriString();



Bu, dosyanın URL'sini döndürerek, kullanıcıların yükledikleri profil resmine erişimini kolaylaştırır.


Özet:


  • Spring Boot kullanarak MultipartFile sınıfı ile dosya yükleme işlemi yapılabilir.
  • Yükleme işlemi için dosyanın boyutu ve formatı gibi kriterler eklenebilir.
  • Yüklenen dosyalar sunucuda saklanabilir ve daha sonra kullanıcıya geri döndürülebilir.
  • Dosyaların güvenli bir şekilde yüklenmesi, benzersiz adlarla saklanması ve dosya türlerinin kontrol edilmesi en iyi uygulamalardır.


Bu özellikler sayesinde kullanıcılar, profil resimlerini kolayca yükleyebilir ve saklayabilir.


25. Dockerize Etme

  • Spring Boot uygulamanızı Docker ile container haline getirin.
  • 25. Dockerize Etme

Spring Boot uygulamanızı Docker ile container haline getirerek, uygulamanızı izole bir ortamda çalıştırabilir, taşınabilir hale getirebilir ve farklı ortamlarda sorunsuzca çalıştırabilirsiniz. Docker, uygulamanızın tüm bağımlılıklarıyla birlikte bir container içinde çalışmasını sağlar.


Aşağıda, Spring Boot uygulamasını Docker ile nasıl container haline getirebileceğinizi adım adım anlatıyorum.


1. Docker Nedir?


Docker, uygulamaları ve bağımlılıklarını içeren container adı verilen izole edilmiş paketler oluşturmanıza ve çalıştırmanıza olanak tanır. Bir Docker container, tüm bağımlılıkları, konfigürasyonları ve işletim sistemi kütüphanelerini içerir. Bu, uygulamanızın farklı ortamlarda çalışırken tutarlı olmasını sağlar.


2. Spring Boot Uygulamanızı Dockerize Etme Adımları


Adım 1: Maven ile Spring Boot Uygulamanızı Build Etme


Öncelikle, Spring Boot uygulamanızın bir JAR dosyasını oluşturmanız gerekiyor. Eğer bir Maven projesi kullanıyorsanız, aşağıdaki komutu çalıştırarak proje yapınızı (build) oluşturabilirsiniz:



mvn clean package



Bu komut, projenizin kök dizininde target klasörü içinde bir JAR dosyası oluşturacaktır. Örneğin:



target/my-spring-boot-app-0.0.1-SNAPSHOT.jar



Adım 2: Dockerfile Oluşturma


Docker, uygulamanızı container içinde çalıştırmak için bir talimat dosyasına (Dockerfile) ihtiyaç duyar. Projenizin kök dizinine bir Dockerfile adlı dosya ekleyin. Bu dosya, Docker’ın uygulamanızı nasıl oluşturacağını ve çalıştıracağını belirler.


Örnek Dockerfile:



# 1. Aşama: Uygulamayı build etme aşaması (Maven ile)

FROM maven:3.8.5-openjdk-17 AS build

WORKDIR /app

COPY pom.xml .

COPY src ./src

RUN mvn clean package -DskipTests


# 2. Aşama: Uygulamayı çalıştırma aşaması (JAR çalıştırma)

FROM openjdk:17-jdk-alpine

WORKDIR /app

COPY --from=build /app/target/my-spring-boot-app-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]



Açıklamalar:

  1. FROM maven:3.8.5-openjdk-17 AS build: İlk aşama olarak, Maven kullanarak uygulamayı build etmek için resmi bir Maven image’ını kullanıyoruz. Bu aşamada, projeyi derleyip bir JAR dosyası oluşturuyoruz.
  2. COPY pom.xml ve COPY src: Maven projesinin yapılandırma ve kaynak dosyalarını Docker imajına kopyalıyoruz.
  3. RUN mvn clean package -DskipTests: Maven kullanarak projeyi derliyoruz ve testleri atlıyoruz.
  4. FROM openjdk:17-jdk-alpine: İkinci aşamada, Java 17 ile çalışacak daha hafif bir OpenJDK Alpine tabanlı image kullanıyoruz.
  5. COPY --from=build: Build edilen JAR dosyasını ikinci aşamaya kopyalıyoruz.
  6. EXPOSE 8080: Uygulamanın çalışacağı portu tanımlıyoruz (Spring Boot varsayılan olarak 8080 portunu kullanır).
  7. ENTRYPOINT: Uygulamanın başlatılma komutunu tanımlıyoruz.


Adım 3: Docker Image Oluşturma


Dockerfile'ı hazırladıktan sonra, Docker image oluşturabilirsiniz. Aşağıdaki komutu çalıştırarak Docker image'ı oluşturun:



docker build -t my-spring-boot-app .



Bu komut, bulunduğunuz dizindeki Dockerfile'ı kullanarak bir Docker image oluşturur ve bu image'a my-spring-boot-app adını verir.


Adım 4: Docker Container Başlatma


Oluşturduğunuz Docker image'ı bir container içinde çalıştırmak için şu komutu kullanın:



docker run -p 8080:8080 my-spring-boot-app



Bu komut, my-spring-boot-app Docker image'ını çalıştırır ve host makinedeki 8080 portunu Docker container içindeki 8080 portuna yönlendirir. Artık uygulamanıza şu URL üzerinden erişebilirsiniz:



http://localhost:8080



Adım 5: Docker Container Yönetimi


Çalışan container'ları görmek için şu komutu kullanabilirsiniz:



docker ps



Eğer bir container'ı durdurmak isterseniz, container ID'sini öğrenip şu komutu kullanabilirsiniz:



docker stop <container-id>



3. Docker Compose Kullanımı


Eğer birden fazla servis (örneğin, Spring Boot ve bir veri tabanı) kullanıyorsanız, Docker Compose ile bu servisleri birlikte çalıştırabilirsiniz. Docker Compose, birden fazla container'ı aynı anda yönetmek için kullanılır.


Adım 6: docker-compose.yml Dosyasını Oluşturma


docker-compose.yml dosyasını projenizin kök dizinine ekleyerek, Spring Boot uygulamanızı bir veri tabanı ile birlikte çalıştırabilirsiniz.


Örnek docker-compose.yml:



version: '3'

services:

  springbootapp:

    image: my-spring-boot-app

    build: .

    ports:

      - "8080:8080"

    depends_on:

      - db


  db:

    image: mysql:8.0

    environment:

      MYSQL_ROOT_PASSWORD: rootpassword

      MYSQL_DATABASE: testdb

      MYSQL_USER: user

      MYSQL_PASSWORD: userpassword

    ports:

      - "3306:3306"



Açıklamalar:

  • services: Her bir servis bir Docker container olarak tanımlanır.
  • springbootapp: Spring Boot uygulamanız.
    • build: Dockerfile kullanarak uygulamanın image’ını oluşturur.
    • depends_on: Bu uygulama veri tabanı container'ı hazır olmadan başlamaz.
  • db: MySQL veri tabanı container'ı.
    • environment: Veri tabanının yapılandırma değişkenleri (şifre, kullanıcı, vs.).


Adım 7: Docker Compose ile Tüm Servisleri Başlatma


Aşağıdaki komutla hem Spring Boot uygulamanızı hem de MySQL veri tabanını aynı anda başlatabilirsiniz:



docker-compose up



Bu komut, docker-compose.yml dosyasındaki tüm servisleri başlatır ve Spring Boot uygulamanız veri tabanı ile birlikte çalışmaya başlar.


4. Docker Image'i Docker Hub'a Push Etme


Docker image'inizi diğer kullanıcılarla paylaşmak için Docker Hub’a yükleyebilirsiniz. Bunun için önce image'inizi etiketlemeniz, sonra da docker push komutunu kullanmanız gerekir.


Adım 8: Docker Image'i Etiketleme ve Docker Hub'a Push Etme


Docker Hub’a image yüklemeden önce image’inizi etiketleyin:



docker tag my-spring-boot-app your-dockerhub-username/my-spring-boot-app



Ardından Docker Hub’a image’inizi push edin:



docker push your-dockerhub-username/my-spring-boot-app



Özet:


  • Docker ile Spring Boot uygulamanızı container haline getirerek, uygulamanızı her ortamda sorunsuzca çalıştırabilirsiniz.
  • Dockerfile kullanarak Spring Boot uygulamanızı build edip, bir Docker image haline getirebilir ve container içinde çalıştırabilirsiniz.
  • Docker Compose kullanarak, birden fazla servisi (örneğin, Spring Boot ve veri tabanı) aynı anda çalıştırabilirsiniz.
  • Docker container'larını docker ps, docker stop gibi komutlarla yönetebilirsiniz.


Bu yöntemler sayesinde Spring Boot uygulamanız taşınabilir hale gelir ve her ortamda tutarlı bir şekilde çalışır.


26. API Gateway ve Microservices

  • Spring Cloud kullanarak mikroservis mimarisi oluşturun.
  • 26. API Gateway ve Mikroservisler


Mikroservis Mimarisi, uygulamaların bağımsız olarak dağıtılabilir, küçük ve birbirinden bağımsız servislerden oluştuğu bir yaklaşımdır. Mikroservis mimarisinde servisler, işlevlerine göre ayrılır ve her biri bağımsız olarak geliştirilir, test edilir, dağıtılır ve ölçeklenir. Spring Cloud ise mikroservis mimarilerini oluşturmak ve yönetmek için güçlü araçlar sunar.


Bir API Gateway, mikroservis mimarisinde tüm isteklerin merkezi bir noktadan yönlendirilmesini sağlar. API Gateway, gelen istekleri uygun mikroservislere yönlendirir ve genellikle yetkilendirme, güvenlik, yük dengeleme gibi işlemleri de yönetir.


Aşağıda Spring Cloud kullanarak nasıl bir mikroservis mimarisi oluşturabileceğinizi, API Gateway ve servislerin entegrasyonunu adım adım gösteriyorum.


1. Spring Cloud API Gateway Nedir?


API Gateway, istemcilerden gelen istekleri alır ve bu istekleri uygun mikroservislere yönlendirir. Spring Cloud'da Spring Cloud Gateway kullanarak bu işlevi gerçekleştirebilirsiniz. API Gateway, mikroservislerin karmaşıklığını gizleyerek dış dünyaya daha basit bir API sunar.


API Gateway'in Görevleri:

  • İstek yönlendirme (Routing)
  • Güvenlik (Authentication ve Authorization)
  • Yük dengeleme (Load Balancing)
  • İzleme (Monitoring)
  • Hata yönetimi (Circuit Breaker)


2. Spring Cloud ile Mikroservis Mimarisi Oluşturma


Aşağıdaki adımlarda bir API Gateway ve birkaç mikroservis oluşturacağız.


Proje Adımları:

  • API Gateway: İstekleri mikroservislere yönlendiren merkezi nokta.
  • Kullanıcı Servisi: Kullanıcı bilgilerini yöneten mikroservis.
  • Sipariş Servisi: Sipariş işlemlerini yöneten mikroservis.


Adım 1: API Gateway Uygulamasını Oluşturma


Spring Cloud Gateway kullanarak API Gateway uygulamasını oluşturmak için Spring Initializr'dan şu bağımlılıkları seçerek yeni bir Spring Boot projesi oluşturun:

  • Spring Boot DevTools
  • Spring Cloud Gateway
  • Spring Boot Actuator


application.properties dosyasını yapılandırın:



server.port=8080


# API Gateway Route Tanımları

spring.cloud.gateway.routes[0].id=user-service

spring.cloud.gateway.routes[0].uri=http://localhost:8081

spring.cloud.gateway.routes[0].predicates[0]=Path=/users/**


spring.cloud.gateway.routes[1].id=order-service

spring.cloud.gateway.routes[1].uri=http://localhost:8082

spring.cloud.gateway.routes[1].predicates[0]=Path=/orders/**



Bu yapılandırma, 8080 portunda çalışan bir API Gateway uygulaması oluşturur. Gelen istekleri, URI'lerine göre farklı mikroservislere yönlendirir:

  • /users/**: Kullanıcı servisine yönlendirilir (port 8081).
  • /orders/**: Sipariş servisine yönlendirilir (port 8082).


Adım 2: Kullanıcı Servisi (User Service) Oluşturma


Kullanıcı bilgilerini yönetecek bir mikroservis oluşturun. Spring Initializr kullanarak şu bağımlılıkları seçerek yeni bir Spring Boot projesi oluşturun:

  • Spring Web
  • Spring Data JPA (isteğe bağlı)
  • H2 Database (isteğe bağlı)


application.properties dosyası:



server.port=8081

spring.application.name=user-service



Örnek UserController:



import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RestController;


@RestController

@RequestMapping("/users")

public class UserController {


    @GetMapping("/{id}")

    public String getUserById(@PathVariable String id) {

        return "Kullanıcı: " + id;

    }

}



Bu basit kullanıcı servisi, bir kullanıcı kimliği ile sorgulandığında kullanıcı bilgilerini döner.


Adım 3: Sipariş Servisi (Order Service) Oluşturma


Sipariş işlemlerini yönetecek bir mikroservis oluşturun. Spring Initializr kullanarak şu bağımlılıkları seçerek yeni bir Spring Boot projesi oluşturun:

  • Spring Web
  • Spring Data JPA (isteğe bağlı)
  • H2 Database (isteğe bağlı)


application.properties dosyası:



server.port=8082

spring.application.name=order-service



Örnek OrderController:



import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RestController;


@RestController

@RequestMapping("/orders")

public class OrderController {


    @GetMapping("/{id}")

    public String getOrderById(@PathVariable String id) {

        return "Sipariş: " + id;

    }

}



Bu servis, sipariş kimliği ile sorgulandığında ilgili sipariş bilgilerini döner.


3. API Gateway Üzerinden Mikroservislere Erişim


Artık iki mikroservis ve bir API Gateway'e sahipsiniz. Gateway üzerinden servislerinize erişmek için aşağıdaki URL'leri kullanabilirsiniz:


  • Kullanıcı servisine erişmek için:

  •   http://localhost:8080/users/1


  • Sipariş servisine erişmek için:

  •   http://localhost:8080/orders/100


API Gateway, gelen istekleri ilgili mikroservislere yönlendirir.


4. Load Balancing (Yük Dengeleme)


Spring Cloud, API Gateway üzerinden gelen istekleri farklı mikroservis instancelerine dağıtmak için Eureka Server ve Ribbon ile yük dengeleme sağlar. Eureka bir servis keşif mekanizmasıdır ve her mikroservis kayıt olur. Gateway, Eureka üzerinden mikroservisleri keşfeder ve istekleri dağıtır.


Eureka Server Kurulumu


Spring Initializr ile yeni bir proje oluşturun ve aşağıdaki bağımlılıkları seçin:

  • Eureka Server
  • Spring Boot DevTools


application.properties dosyası:



server.port=8761

eureka.client.register-with-eureka=false

eureka.client.fetch-registry=false



Eureka Server'ı etkinleştirmek için @EnableEurekaServer anotasyonunu kullanın:



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;


@SpringBootApplication

@EnableEurekaServer

public class EurekaServerApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaServerApplication.class, args);

    }

}



Mikroservisleri Eureka'ya Kayıt Etme


Kullanıcı ve Sipariş servislerini Eureka'ya kaydetmek için, bu servislerin application.properties dosyalarına aşağıdaki yapılandırmaları ekleyin:



eureka.client.service-url.default-zone=http://localhost:8761/eureka



Ayrıca, @EnableEurekaClient anotasyonunu eklemeyi unutmayın:



import org.springframework.cloud.netflix.eureka.EnableEurekaClient;


@SpringBootApplication

@EnableEurekaClient

public class UserServiceApplication {

    public static void main(String[] args) {

        SpringApplication.run(UserServiceApplication.class, args);

    }

}



API Gateway Üzerinden Eureka ile Yük Dengeleme


API Gateway'in application.properties dosyasına Eureka Client entegrasyonu ekleyin:



eureka.client.service-url.default-zone=http://localhost:8761/eureka

spring.cloud.gateway.discovery.locator.enabled=true



Bu ayarla, API Gateway, Eureka'dan servisleri otomatik olarak keşfeder ve istekleri yük dengeleme ile yönlendirir.


5. Circuit Breaker Kullanımı


Mikroservisler arası isteklerde bir servis çökerse veya yanıt vermezse, Circuit Breaker kullanarak bu durumu yönetebilirsiniz. Resilience4j gibi kütüphanelerle Spring Cloud Gateway'e circuit breaker ekleyebilirsiniz.


Örnek Circuit Breaker Yapılandırması


application.properties dosyasına aşağıdaki ayarları ekleyin:



spring.cloud.gateway.routes[0].filters[0]=CircuitBreaker=name=userServiceCircuitBreaker,fallbackUri=/fallback



Fallback metodu, bir servis başarısız olduğunda çalışacak olan yedek işlemi tanımlar:



@RestController

public class FallbackController {


    @GetMapping("/fallback")

    public String fallback() {

        return "Servis geçici olarak kullanılamıyor.";

    }

}



Özet:


  • Spring Cloud Gateway, mikroservis mimarisinde tüm isteklerin merkezi bir noktadan yönetilmesini sağlar.
  • API Gateway, gelen istekleri mikroservislere yönlendirir, güvenlik, yük dengeleme ve hata yönetimi gibi görevleri yerine getirir.
  • **- Eureka ise bir service discovery (servis keşfi) aracı olarak mikroservislerin birbirlerini dinamik olarak bulmasını ve API Gateway gibi merkezi servislerin bu mikroservislere ulaşmasını sağlar.
  • Circuit Breaker, servisler arasında oluşabilecek hataları yönetir ve bir servis başarısız olduğunda devreye girerek diğer servislerin sağlıklı çalışmasını sağlar.


6. Servis Keşfi (Service Discovery) ile Dinamik Yönlendirme


Mikroservislerin sayısı arttıkça ve her bir servis farklı ortamlarda, IP adreslerinde çalıştırıldıkça, servislerin sabit IP adresleri ile yönetilmesi zorlaşır. Eureka gibi servis keşfi araçları, bu dinamik yapıyı yönetmek için kullanılır.


Servis Keşfi Mekanizması:

  • Her mikroservis başlatıldığında, kendisini Eureka Server’a kaydeder.
  • Eureka Server, servislerin adreslerini ve durumlarını takip eder.
  • API Gateway veya diğer servisler, Eureka üzerinden mikroservislerin yerlerini dinamik olarak keşfeder ve isteklerini yönlendirir.


Adım 1: Eureka Server Üzerindeki Servislerin Görüntülenmesi


Eureka Server’ı başlattığınızda, http://localhost:8761/ adresine giderek kayıtlı mikroservisleri görebilirsiniz. Bu arayüzde, aktif mikroservislerin durumu ve adresleri listelenir.


Adım 2: API Gateway ile Dinamik Yönlendirme


Spring Cloud Gateway’i Eureka ile entegre ettiğimizde, mikroservisler Eureka üzerinde kayıtlı olduğunda, API Gateway bu servisleri dinamik olarak keşfeder ve istekleri ilgili servise yönlendirir. Daha önce tanımladığımız application.properties dosyasındaki şu satır, API Gateway’in Eureka üzerinden mikroservisleri keşfetmesini sağlar:



spring.cloud.gateway.discovery.locator.enabled=true



Bu sayede, örneğin bir kullanıcı servisi Eureka'ya kayıtlı olduğunda, API Gateway şu URI yolunu kullanarak dinamik olarak istekleri yönlendirebilir:



http://localhost:8080/USER-SERVICE/users/1



Burada USER-SERVICE, Eureka'da kayıtlı olan servis adıdır. Gateway, servisin hangi IP ve portta olduğunu dinamik olarak öğrenir ve istekleri yönlendirir.


7. Load Balancing (Yük Dengeleme)


Bir mikroservisin birden fazla instance'ı olduğunda (örneğin, aynı servisin farklı portlarda çalışan birden fazla kopyası), API Gateway bu instance'lara gelen istekleri dengeli bir şekilde dağıtabilir. Bu işleme load balancing (yük dengeleme) denir.


Spring Cloud, yük dengeleme için Ribbon kütüphanesini sunar. Ancak Spring Cloud’ın yeni sürümlerinde Spring Cloud LoadBalancer daha yaygın olarak kullanılır. Eureka üzerinden servis keşfi yapıldığında, bu yük dengeleme otomatik olarak uygulanır.


Yük Dengeleme ile Yönlendirme


Eğer kullanıcı servisi (user-service) iki farklı instance’da çalışıyorsa (örneğin, port 8081 ve 8083), API Gateway bu instance'lara gelen istekleri sırayla ya da belirli bir dengeleme algoritmasına göre dağıtacaktır.



spring:

  cloud:

    gateway:

      discovery:

        locator:

          enabled: true

      routes:

        - id: user-service

          uri: lb://USER-SERVICE



Bu ayarla, lb://USER-SERVICE yoluyla yük dengeleme aktif hale getirilir ve istekler Eureka'da kayıtlı olan tüm USER-SERVICE instance'larına dengeli bir şekilde dağıtılır.


8. Circuit Breaker ve Hata Yönetimi


Mikroservis mimarisinde, bir servis başarısız olursa, bu durum diğer mikroservislerin sağlığını da olumsuz etkileyebilir. Bu gibi durumlarda Circuit Breaker kullanarak arızalı servislere olan istekleri geçici olarak durdurabilirsiniz. Resilience4j Spring Cloud Gateway ile birlikte kullanılarak Circuit Breaker mekanizması entegre edilebilir.


Adım 1: Resilience4j Bağımlılığı Ekleyin


pom.xml dosyasına şu bağımlılığı ekleyin:



<dependency>

    <groupId>io.github.resilience4j</groupId>

    <artifactId>resilience4j-spring-boot2</artifactId>

</dependency>



Adım 2: Circuit Breaker Yapılandırması


API Gateway üzerindeki belirli bir rota için Circuit Breaker filtresi ekleyin. Bu yapılandırma, kullanıcı servisi başarısız olduğunda bir yedek (fallback) rotaya yönlendirilmesini sağlar.



spring.cloud.gateway.routes[0].id=user-service

spring.cloud.gateway.routes[0].uri=lb://USER-SERVICE

spring.cloud.gateway.routes[0].predicates[0]=Path=/users/**

spring.cloud.gateway.routes[0].filters[0]=CircuitBreaker=name=userCircuitBreaker,fallbackUri=/fallback



Fallback işlemi, kullanıcı servisi başarısız olduğunda yedek bir işlemi devreye sokar:



@RestController

public class FallbackController {


    @GetMapping("/fallback")

    public String fallback() {

        return "Kullanıcı servisi şu anda kullanılamıyor. Lütfen daha sonra tekrar deneyin.";

    }

}



Bu sayede kullanıcı servisi başarısız olduğunda veya yanıt veremediğinde, istemciler hata yerine bu yedek rotaya yönlendirilir.


9. API Gateway ile Güvenlik


API Gateway ile gelen tüm isteklerin merkezi olarak güvenliğini sağlamak da mümkündür. Bu, genellikle JWT (JSON Web Token) veya OAuth 2.0 kullanılarak yapılır.


Adım 1: Spring Security ile API Gateway Güvenliği


API Gateway'e güvenlik eklemek için Spring Security'yi kullanabilirsiniz. Örneğin, gelen tüm isteklerde JWT doğrulaması yapmak için şu adımları izleyebilirsiniz:


pom.xml Bağımlılıkları:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-security</artifactId>

</dependency>



Güvenlik Yapılandırması:



import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;


@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Override

    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()

            .authorizeRequests()

            .antMatchers("/users/**").authenticated()

            .antMatchers("/orders/**").authenticated()

            .and()

            .oauth2ResourceServer()

            .jwt();

    }

}



Bu güvenlik yapılandırması ile, kullanıcı ve sipariş servislerine yapılan tüm isteklerde JWT doğrulaması yapılacaktır. Spring Security'yi kullanarak tüm mikroservislerinize merkezi bir güvenlik yönetimi sağlayabilirsiniz.


10. Observability ve Monitoring


Mikroservis mimarisinde observability (gözlemlenebilirlik) ve monitoring (izleme) çok önemlidir. Spring Boot Actuator ve Spring Cloud Sleuth gibi araçlarla mikroservislerin durumlarını ve performanslarını izleyebilirsiniz. Ayrıca Zipkin ile dağıtık izleme (distributed tracing) yaparak, her bir isteğin mikroservisler arasında nasıl yönlendirildiğini ve nerede gecikmeler olduğunu izleyebilirsiniz.


Actuator ve Sleuth Kullanımı


Spring Boot Actuator kullanarak mikroservislerinizin sağlık durumlarını ve performans metriklerini izleyebilirsiniz.



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>


<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-sleuth</artifactId>

</dependency>



Özet:


  • Spring Cloud ile API Gateway ve mikroservis mimarisi oluşturmak, büyük ölçekli uygulamaların yönetimini ve ölçeklenebilirliğini sağlar.
  • API Gateway, mikroservislere gelen tüm istekleri merkezi olarak yönetir ve yönlendirir.
  • Eureka, mikroservislerin dinamik olarak keşfedilmesini ve yük dengeleme yapılmasını sağlar.
  • Circuit Breaker ve Resilience4j gibi araçlar, mikroservisler arasındaki hataları yönetmeye ve sistemin güvenilirliğini artırmaya yardımcı olur.
  • Spring Security ile API Gateway’e merkezi güvenlik ekleyerek, mikroservislerin güvenli bir şekilde kullanılmasını sağlayabilirsiniz.


Bu yöntemlerle mikroservislerinizi sorunsuz bir şekilde yönetebilir, ölçeklendirebilir ve güvenli hale getirebilirsiniz.


27. Circuit Breaker - Resilience4j

  • Uygulamanızda hata toleransı eklemek için Circuit Breaker desenini kullanın.
  • 27. Circuit Breaker Deseni - Resilience4j


Circuit Breaker (Devre Kesici) deseni, mikroservis mimarisinde hata toleransı sağlamak için kullanılan bir dayanıklılık desenidir. Mikroservislerin arızalı ya da aşırı yük altında olan bir servise sürekli istek göndermesini engelleyerek sistemi korur. Resilience4j, Spring Boot ile birlikte Circuit Breaker, Rate Limiter, Retry ve Bulkhead gibi dayanıklılık desenlerini uygulamak için kullanılan hafif ve güçlü bir kütüphanedir.


Circuit Breaker, bir servisin çalışıp çalışmadığını kontrol ederek, arızalı olduğunda devreyi keser ve belirli bir süre boyunca isteğin yapılmasını engeller. Servis tekrar düzelirse devreyi yeniden açar.


1. Resilience4j Nedir?


Resilience4j, mikroservislerin dayanıklılığını artırmak için çeşitli desenler sunar:

  • Circuit Breaker: Bir servise yapılan istekler belirli bir hata oranını aşarsa devreyi kapatır ve yeni isteklerin yapılmasını geçici olarak durdurur.
  • Retry: Başarısız olan işlemleri tekrar denemeyi sağlar.
  • Rate Limiter: İsteklerin hızını sınırlayarak sistemin aşırı yüklenmesini engeller.
  • Bulkhead: Bir serviste aşırı yüklenme olduğunda, bu yükün diğer servisleri etkilemesini engeller.


2. Resilience4j ile Circuit Breaker Entegrasyonu


Aşağıda Resilience4j Circuit Breaker ile mikroservislerinizde hata toleransı sağlamak için nasıl kullanabileceğinizi anlatıyorum.


Adım 1: Projeye Resilience4j Bağımlılıklarını Ekleme


pom.xml dosyanıza Resilience4j ve Spring Boot Starter AOP bağımlılıklarını ekleyin:



<dependency>

    <groupId>io.github.resilience4j</groupId>

    <artifactId>resilience4j-spring-boot2</artifactId>

    <version>1.7.1</version>

</dependency>


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-aop</artifactId>

</dependency>



Bu bağımlılıkları ekleyerek Resilience4j ile Circuit Breaker mekanizmasını kullanmaya başlayabilirsiniz.


Adım 2: Circuit Breaker Kullanımı için Konfigürasyon


Circuit Breaker, bir servisin başarısız olduğunda nasıl davranacağını belirler. Bunu konfigüre etmek için application.properties veya application.yml dosyanıza ekleme yapabilirsiniz.


application.yml Örneği:



resilience4j.circuitbreaker:

  instances:

    userService:

      slidingWindowSize: 10

      failureRateThreshold: 50

      waitDurationInOpenState: 5000

      permittedNumberOfCallsInHalfOpenState: 3

      slidingWindowType: COUNT_BASED

      minimumNumberOfCalls: 5



Bu ayarlar şu şekilde çalışır:

  • slidingWindowSize: Circuit Breaker'ın ne kadar isteği analiz edeceğini belirler (örn. 10 istek).
  • failureRateThreshold: Hatalı istek oranı %50'yi aşarsa devre kapanır.
  • waitDurationInOpenState: Devre kapalı olduğunda ne kadar süre bekleyeceğini belirler (5000ms = 5 saniye).
  • permittedNumberOfCallsInHalfOpenState: Devre kapandıktan sonra, devrenin tekrar açılmadan önce kaç istek yapabileceğini belirler.
  • slidingWindowType: Pencere tipi COUNT_BASED olarak ayarlanmış; yani sabit sayıda istek baz alınarak devre kontrol edilir.


Adım 3: Circuit Breaker ile Servisleri Koruma


Circuit Breaker’ı servis çağrılarınızı korumak için kullanabilirsiniz. Örneğin, bir dış API çağrısının devre kesiciyle korunmasını sağlayalım.


UserService: Dış bir servisi çağıran örnek servis.



import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;

import org.springframework.stereotype.Service;

import org.springframework.web.client.RestTemplate;


@Service

public class UserService {


    private final RestTemplate restTemplate = new RestTemplate();


    @CircuitBreaker(name = "userService", fallbackMethod = "fallbackGetUser")

    public String getUserById(String id) {

        String url = "http://external-service/users/" + id;

        return restTemplate.getForObject(url, String.class); // Dış servis çağrısı

    }


    // Circuit Breaker çalıştığında devreye girecek fallback metodu

    public String fallbackGetUser(String id, Throwable t) {

        return "Kullanıcı bilgileri şu anda alınamıyor. Lütfen daha sonra tekrar deneyin.";

    }

}



Açıklamalar:

  • @CircuitBreaker(name = "userService", fallbackMethod = "fallbackGetUser"): Bu anotasyon, devre kesici mekanizmasını devreye sokar ve userService adında bir Circuit Breaker tanımlar. Eğer servis başarısız olursa, belirtilen fallback metodu devreye girer.
  • fallbackGetUser: Ana servis çağrısı başarısız olduğunda bu metod devreye girer. Kullanıcıya dostça bir hata mesajı döner.


Adım 4: Fallback Metodunun Tanımlanması


Fallback metodu, orijinal servis çağrısı başarısız olduğunda devreye giren yedek işlemdir. Yukarıdaki örnekte, dış API başarısız olursa fallbackGetUser metodu çalıştırılır.



public String fallbackGetUser(String id, Throwable t) {

    return "Kullanıcı bilgileri şu anda alınamıyor. Lütfen daha sonra tekrar deneyin.";

}



Bu yedek metod, hata mesajlarını kontrol ederek kullanıcıya bilgi verebilir ya da başka bir kaynakta yedek veri sunabilir.


3. Circuit Breaker'ın Durumları


Circuit Breaker üç farklı durumda olabilir:

  • CLOSED (Kapalı): Her şey yolunda. İstekler normal şekilde servise iletilir.
  • OPEN (Açık): Çok fazla hata meydana geldi. Devre kesilmiş, istekler yapılmıyor.
  • HALF_OPEN (Yarı Açık): Belirli bir süre sonra tekrar birkaç isteği kabul eder. Eğer bu istekler başarılı olursa devre tekrar kapalı hale gelir.


Bu durumlar, sistemin esnekliğini ve performansını korumak için önemlidir. Circuit Breaker, sistemdeki bir servisin aşırı yüklenmesini engeller ve hizmet kesintisi durumunda kullanıcıya dostça bir geri bildirim sağlar.


4. Resilience4j Dashboard (Opsiyonel)


Resilience4j ile uygulamanızda devre kesicilerin ne durumda olduğunu görsel olarak izlemek için bir dashboard ekleyebilirsiniz. Bunun için Spring Boot Actuator ve Micrometer kullanarak devre kesiciler hakkında metrikler toplayabilirsiniz.


pom.xml Bağımlılığı:



<dependency>

    <groupId>io.github.resilience4j</groupId>

    <artifactId>resilience4j-micrometer</artifactId>

</dependency>


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>



Bu bağımlılıklar ile Spring Boot Actuator üzerinden Resilience4j ile ilgili metrikleri izleyebilir ve servislerinizin ne kadar dayanıklı olduğunu gözlemleyebilirsiniz.


5. Resilience4j Konfigürasyonları


Resilience4j, sadece Circuit Breaker ile sınırlı değildir. Ayrıca Retry, Rate Limiter ve Bulkhead gibi diğer dayanıklılık desenlerini de destekler. Bu desenleri kullanarak mikroservislerinizin performansını ve güvenilirliğini artırabilirsiniz.


a. Retry (Tekrar Deneme):



resilience4j.retry:

  instances:

    userServiceRetry:

      maxAttempts: 3

      waitDuration: 1000



b. Rate Limiter (Hız Sınırlandırıcı):



resilience4j.ratelimiter:

  instances:

    userServiceRateLimiter:

      limitForPeriod: 10

      limitRefreshPeriod: 1s



Bu ayarlar ile servislere yapılan isteklerin sayısını sınırlayarak sistemin aşırı yüklenmesini engelleyebilirsiniz.


Özet:


  • Circuit Breaker deseni, mikroservislerin hata toleransını artırarak başarısız olan servisleri geçici olarak devre dışı bırakır ve sistemin stabil çalışmasını sağlar.
  • Resilience4j, Spring Boot uygulamaları için hafif ve güçlü bir hata toleransı kütüphanesidir.
  • Circuit Breaker başarısız servisleri izler, gerektiğinde devreyi kapatır ve istekleri


28. Spring Boot RESTful API Geliştirme

  • 28. Spring Boot ile RESTful API Geliştirme


Spring Boot kullanarak CRUD (Create, Read, Update, Delete) işlemlerini gerçekleştiren bir RESTful API geliştirmek, servis tabanlı uygulamalarda sıklıkla kullanılan bir yaklaşımdır. Controller, Service, ve Repository katmanlarını kullanarak temiz ve iyi organize edilmiş bir yapı elde edebilirsiniz.


Aşağıda Spring Boot ile temel bir CRUD API geliştirme adımlarını detaylıca anlatıyorum.


1. Proje Yapısı


Spring Boot projelerinde genellikle aşağıdaki katmanları kullanarak bir yapı oluştururuz:

  • Controller: Gelen HTTP isteklerini karşılar ve yanıtları döner.
  • Service: İş mantığını içerir, Controller’dan gelen işlemleri yönetir.
  • Repository: Veritabanı işlemleri bu katmanda gerçekleştirilir.


2. Proje Kurulumu


Spring Boot ile temel bir CRUD API geliştirmek için Spring Initializr üzerinden şu bağımlılıkları seçerek proje oluşturun:

  • Spring Web: REST API geliştirme için.
  • Spring Data JPA: Veritabanı erişimi için.
  • H2 Database: Geliştirme sürecinde kullanılacak hafif bir veritabanı.
  • Lombok: Getter, Setter ve diğer kodları otomatik oluşturmak için.


3. Entity Oluşturma


CRUD işlemleri için basit bir Product (Ürün) sınıfı tanımlayalım. Bu sınıf, veritabanında bir tabloya karşılık gelecek.


Product.java



import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;


import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;


@Data

@AllArgsConstructor

@NoArgsConstructor

@Entity

public class Product {


    @Id

    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;


    private String name;

    private Double price;

}



Açıklamalar:

  • @Entity: Bu sınıfın bir veritabanı tablosuna karşılık geldiğini belirtir.
  • @Id: Birincil anahtar olduğunu belirtir.
  • @GeneratedValue: ID'nin otomatik olarak artırılmasını sağlar.
  • Lombok: @Data, @AllArgsConstructor, @NoArgsConstructor anotasyonları ile getter, setter, constructor gibi metotlar otomatik oluşturulur.


4. Repository Katmanı


Veritabanı işlemleri için Spring Data JPA ile Repository katmanını oluştururuz. Spring Data JPA, CRUD işlemlerini otomatik olarak sağlayan yöntemler sunar.


ProductRepository.java



import org.springframework.data.jpa.repository.JpaRepository;


public interface ProductRepository extends JpaRepository<Product, Long> {

}



Açıklama:

  • JpaRepository: Spring Data JPA tarafından sağlanan bu arayüz, CRUD işlemlerini ve ek SQL işlemlerini gerçekleştiren metotlar sunar.


5. Service Katmanı


Servis katmanı, iş mantığını barındırır. ProductService adında bir servis sınıfı oluşturarak CRUD işlemlerini yönetelim.


ProductService.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import java.util.List;

import java.util.Optional;


@Service

public class ProductService {


    @Autowired

    private ProductRepository productRepository;


    public List<Product> getAllProducts() {

        return productRepository.findAll();

    }


    public Optional<Product> getProductById(Long id) {

        return productRepository.findById(id);

    }


    public Product createProduct(Product product) {

        return productRepository.save(product);

    }


    public Product updateProduct(Long id, Product productDetails) {

        Product product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));


        product.setName(productDetails.getName());

        product.setPrice(productDetails.getPrice());


        return productRepository.save(product);

    }


    public void deleteProduct(Long id) {

        Product product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));

        productRepository.delete(product);

    }

}



Açıklamalar:

  • getAllProducts(): Tüm ürünleri döner.
  • getProductById(): Belirtilen ID'ye sahip ürünü bulur.
  • createProduct(): Yeni bir ürün oluşturur.
  • updateProduct(): Mevcut bir ürünü günceller.
  • deleteProduct(): Ürünü siler.


6. Controller Katmanı


ProductController sınıfı, gelen HTTP isteklerini karşılar ve ProductService kullanarak CRUD işlemlerini gerçekleştirir.


ProductController.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;


import java.util.List;


@RestController

@RequestMapping("/api/products")

public class ProductController {


    @Autowired

    private ProductService productService;


    @GetMapping

    public List<Product> getAllProducts() {

        return productService.getAllProducts();

    }


    @GetMapping("/{id}")

    public ResponseEntity<Product> getProductById(@PathVariable Long id) {

        return productService.getProductById(id)

                .map(ResponseEntity::ok)

                .orElse(ResponseEntity.notFound().build());

    }


    @PostMapping

    public Product createProduct(@RequestBody Product product) {

        return productService.createProduct(product);

    }


    @PutMapping("/{id}")

    public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody Product productDetails) {

        try {

            Product updatedProduct = productService.updateProduct(id, productDetails);

            return ResponseEntity.ok(updatedProduct);

        } catch (RuntimeException e) {

            return ResponseEntity.notFound().build();

        }

    }


    @DeleteMapping("/{id}")

    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {

        try {

            productService.deleteProduct(id);

            return ResponseEntity.noContent().build();

        } catch (RuntimeException e) {

            return ResponseEntity.notFound().build();

        }

    }

}



Açıklamalar:

  • @RestController: Bu sınıfın bir REST API denetleyicisi olduğunu belirtir.
  • @RequestMapping("/api/products"): API'nin temel yolunu tanımlar.
  • @GetMapping, @PostMapping, @PutMapping, @DeleteMapping: HTTP metoduna göre API rotalarını tanımlar.
  • ResponseEntity: API yanıtını özelleştirmek ve HTTP statü kodları ile birlikte döndürmek için kullanılır.


7. H2 Veritabanı Yapılandırması


Geliştirme ortamında hızlı testler yapmak için H2 veritabanını kullanabilirsiniz. H2 veritabanını yapılandırmak için application.properties dosyasına aşağıdaki ayarları ekleyin:


application.properties



spring.datasource.url=jdbc:h2:mem:testdb

spring.datasource.driverClassName=org.h2.Driver

spring.datasource.username=sa

spring.datasource.password=password

spring.h2.console.enabled=true

spring.jpa.hibernate.ddl-auto=update



Bu ayarlar sayesinde uygulamanız, hafızada çalışan bir H2 veritabanı kullanacak ve her çalıştırıldığında tablolar otomatik olarak oluşturulacaktır.


8. API'yi Test Etme


Artık uygulamanız çalıştığında aşağıdaki rotalar üzerinden CRUD işlemlerini gerçekleştirebilirsiniz:


1. Ürünleri Listeleme

  • GET isteği:

  •   http://localhost:8080/api/products


2. Belirli Bir Ürünü Getirme

  • GET isteği:

  •   http://localhost:8080/api/products/{id}


3. Yeni Bir Ürün Oluşturma

  • POST isteği, JSON formatında ürün verisi gönderilir:

  •   http://localhost:8080/api/products



{

  "name": "Laptop",

  "price": 1500.00

}



4. Mevcut Bir Ürünü Güncelleme

  • PUT isteği:

  •   http://localhost:8080/api/products/{id}



{

  "name": "Updated Laptop",

  "price": 1600.00

}



5. Bir Ürünü Silme

  • DELETE isteği:

  •   http://localhost:8080/api/products/{id}


9. Swagger İle API Dokümantasyonu (Opsiyonel)


Spring Boot projenize Swagger ekleyerek API'nizi dokümante edebilir ve kolayca test edebilirsiniz. Bunun için aşağıdaki bağımlılığı pom.xml dosyanıza ekleyin:



<dependency>

    <groupId>io.springfox</groupId>

    <artifactId>springfox-boot-starter</artifactId>

    <version>3.0.0</version>

</dependency>



  1. **DTO kullanımı

DTO (Data Transfer Object) Kullanarak Veri Transferi


Spring Boot projelerinde DTO (Data Transfer Object) kullanarak veritabanı modellerini (entity sınıfları) dışarıya açmak yerine, veri transferi için özel sınıflar kullanmak en iyi uygulamalardan biridir. DTO'lar, veritabanı yapılarını gizler ve sadece gerekli olan bilgileri dış dünyaya sunar. Ayrıca, güvenlik, performans ve esneklik açısından önemli bir rol oynar.


Aşağıda, DTO kullanarak nasıl veri transferi yapabileceğinizi anlatıyorum. Entity sınıfını direkt dışarıya açmak yerine DTO sınıflarıyla bu veriyi nasıl dönüştüreceğinizi ve MapStruct kullanarak bu dönüşümleri nasıl kolaylaştıracağınızı göstereceğim.


1. DTO Sınıfını Oluşturma


Bir DTO (Data Transfer Object), genellikle dış dünyaya (örneğin, REST API ile) sunulacak veriyi taşımak için kullanılır. İlk olarak, ProductDTO sınıfını oluşturalım.


ProductDTO.java



public class ProductDTO {


    private String name;

    private double price;


    // Getters and Setters

    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public double getPrice() {

        return price;

    }


    public void setPrice(double price) {

        this.price = price;

    }

}



2. Entity ve DTO Dönüşümleri


DTO'lar ve Entity sınıfları arasında veri dönüşümlerini manuel olarak yapabilir veya bu işlemleri otomatikleştiren kütüphaneler kullanabilirsiniz. Manuel olarak DTO'ya dönüşümü aşağıda gösterdiğim gibi yapabilirsiniz, ancak bu dönüşümleri otomatikleştirmek için MapStruct gibi araçlar kullanmak daha verimli olacaktır.


Manuel Dönüşüm (Entity to DTO)


ProductService içinde, entity sınıflarını ProductDTO'ya dönüştüren ve DTO'ları entity'ye dönüştüren metotlar ekleyelim.


ProductService.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import java.util.List;

import java.util.Optional;

import java.util.stream.Collectors;


@Service

public class ProductService {


    @Autowired

    private ProductRepository productRepository;


    // Tüm ürünleri getirir ve DTO'ya dönüştürür

    public List<ProductDTO> getAllProducts() {

        List<Product> products = productRepository.findAll();

        return products.stream()

                .map(this::convertToDTO)

                .collect(Collectors.toList());

    }


    // ID'ye göre ürünü getirir ve DTO'ya dönüştürür

    public Optional<ProductDTO> getProductById(Long id) {

        Optional<Product> product = productRepository.findById(id);

        return product.map(this::convertToDTO);

    }


    // Ürün oluşturur ve entity'den DTO'ya dönüşümü sağlar

    public ProductDTO createProduct(ProductDTO productDTO) {

        Product product = convertToEntity(productDTO);

        Product savedProduct = productRepository.save(product);

        return convertToDTO(savedProduct);

    }


    // Ürün günceller ve entity'den DTO'ya dönüşümü sağlar

    public ProductDTO updateProduct(Long id, ProductDTO productDetails) {

        Product product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));


        product.setName(productDetails.getName());

        product.setPrice(productDetails.getPrice());


        Product updatedProduct = productRepository.save(product);

        return convertToDTO(updatedProduct);

    }


    public void deleteProduct(Long id) {

        Product product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));

        productRepository.delete(product);

    }


    // Entity'den DTO'ya dönüşüm

    private ProductDTO convertToDTO(Product product) {

        ProductDTO productDTO = new ProductDTO();

        productDTO.setName(product.getName());

        productDTO.setPrice(product.getPrice());

        return productDTO;

    }


    // DTO'dan Entity'ye dönüşüm

    private Product convertToEntity(ProductDTO productDTO) {

        Product product = new Product();

        product.setName(productDTO.getName());

        product.setPrice(productDTO.getPrice());

        return product;

    }

}



3. Controller'da DTO Kullanımı


ProductController sınıfını güncelleyerek ProductDTO sınıflarını kullanacak şekilde düzenleyelim. Bu sayede, API dış dünyaya sadece DTO objelerini döndürür, Entity'yi direkt açmaz.


ProductController.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;


import java.util.List;


@RestController

@RequestMapping("/api/products")

public class ProductController {


    @Autowired

    private ProductService productService;


    @GetMapping

    public List<ProductDTO> getAllProducts() {

        return productService.getAllProducts();

    }


    @GetMapping("/{id}")

    public ResponseEntity<ProductDTO> getProductById(@PathVariable Long id) {

        return productService.getProductById(id)

                .map(ResponseEntity::ok)

                .orElse(ResponseEntity.notFound().build());

    }


    @PostMapping

    public ProductDTO createProduct(@RequestBody ProductDTO productDTO) {

        return productService.createProduct(productDTO);

    }


    @PutMapping("/{id}")

    public ResponseEntity<ProductDTO> updateProduct(@PathVariable Long id, @RequestBody ProductDTO productDetails) {

        try {

            ProductDTO updatedProduct = productService.updateProduct(id, productDetails);

            return ResponseEntity.ok(updatedProduct);

        } catch (RuntimeException e) {

            return ResponseEntity.notFound().build();

        }

    }


    @DeleteMapping("/{id}")

    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {

        try {

            productService.deleteProduct(id);

            return ResponseEntity.noContent().build();

        } catch (RuntimeException e) {

            return ResponseEntity.notFound().build();

        }

    }

}



4. MapStruct Kullanarak Dönüşümleri Otomatikleştirme (Opsiyonel)


MapStruct, DTO ile Entity sınıfları arasındaki dönüşümleri otomatikleştiren bir kütüphanedir. Manuel dönüşüm metotları yerine, MapStruct kullanarak kodunuzu daha temiz ve bakımı kolay hale getirebilirsiniz.


Adım 1: MapStruct Bağımlılığını Ekleyin


pom.xml dosyanıza aşağıdaki bağımlılıkları ekleyin:



<dependency>

    <groupId>org.mapstruct</groupId>

    <artifactId>mapstruct</artifactId>

    <version>1.4.2.Final</version>

</dependency>

<dependency>

    <groupId>org.projectlombok</groupId>

    <artifactId>lombok</artifactId>

    <version>1.18.12</version>

    <scope>provided</scope>

</dependency>

<dependency>

    <groupId>org.mapstruct</groupId>

    <artifactId>mapstruct-processor</artifactId>

    <version>1.4.2.Final</version>

    <scope>provided</scope>

</dependency>



Adım 2: DTO ile Entity Arasında Dönüşüm Sağlayan Mapper


MapStruct ile entity ve DTO sınıfları arasında dönüşümü sağlayan bir mapper oluşturun.


ProductMapper.java



import org.mapstruct.Mapper;

import org.mapstruct.factory.Mappers;


@Mapper

public interface ProductMapper {


    ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);


    ProductDTO productToProductDTO(Product product);


    Product productDTOToProduct(ProductDTO productDTO);

}



Adım 3: Service Katmanında MapStruct Kullanımı


Artık manuel dönüşüm yapmak yerine, ProductMapper'ı kullanarak dönüşümleri gerçekleştirebilirsiniz.


ProductService.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import java.util.List;

import java.util.Optional;

import java.util.stream.Collectors;


@Service

public class ProductService {


    @Autowired

    private ProductRepository productRepository;


    private final ProductMapper productMapper = ProductMapper.INSTANCE;


    public List<ProductDTO> getAllProducts() {

        List<Product> products = productRepository.findAll();

        return products.stream()

                .map(productMapper::productToProductDTO)

                .collect(Collectors.toList());

    }


    public Optional<ProductDTO> getProductById(Long id) {

        Optional<Product> product = productRepository.findById(id);

        return product.map(productMapper::productToProductDTO);

    }


    public ProductDTO createProduct(ProductDTO productDTO) {

        Product product = productMapper.productDTOToProduct(productDTO);

        Product savedProduct = productRepository.save(product);

        return productMapper.productToProductDTO(savedProduct);

    }


    public ProductDTO updateProduct(Long id, ProductDTO productDetails) {

        Product product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));


        product.setName(productDetails.getName());

        product.setPrice(productDetails.getPrice());


        Product updatedProduct = productRepository.save(product);

        return productMapper.productToProductDTO(updatedProduct);

    }


    public void delete

### 30. **Model Mapper ile Dönüşüm**

- **ModelMapper** ya da **MapStruct** kullanarak DTO ve entity sınıfları arasında dönüşüm sağlayın:

  ```java

  ModelMapper modelMapper = new ModelMapper();

  ProductDTO productDTO = modelMapper.map(product, ProductDTO.class);

  


31. Hateoas (Hypermedia as the Engine of Application State)

  • REST API'ler için HATEOAS kullanarak hypermedia tabanlı kaynaklara bağlantılar ekleyin:
  • HATEOAS ile Hypermedia Tabanlı REST API Geliştirme


HATEOAS (Hypermedia as the Engine of Application State), REST API'lerde kaynaklar arasındaki ilişkileri ve etkileşimleri belirtmek için kullanılır. Bu, her kaynağın diğer kaynaklara olan bağlantılarını içerir ve istemcilerin, bir API'nin nasıl kullanılacağını anlamasına yardımcı olur. Spring Boot, Spring HATEOAS kütüphanesi ile HATEOAS desteğini sağlar.


Spring HATEOAS, her kaynağa bağlantılar (links) ekleyerek istemcilerin bu kaynaklar ile nasıl etkileşime geçeceğini gösterir. Aşağıda, bir Spring Boot uygulamasında HATEOAS kullanarak API'lere hypermedia tabanlı bağlantılar eklemeyi anlatıyorum.


1. Proje Yapılandırması


İlk olarak, Spring Boot projenize Spring HATEOAS bağımlılığını ekleyin.


pom.xml Bağımlılığı:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-hateoas</artifactId>

</dependency>



2. HATEOAS ile Controller'da Hypermedia Bağlantıları Eklemek


Aşağıda bir ürünün (Product) detayını dönen bir API örneği yer alıyor. API yanıtına HATEOAS bağlantıları ekleyerek, istemcilerin aynı kaynağa veya ilgili diğer kaynaklara nasıl erişebileceğini gösteriyoruz.


ProductController.java



import org.springframework.hateoas.EntityModel;

import org.springframework.hateoas.Link;

import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;


import java.util.List;

import java.util.stream.Collectors;


import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;


@RestController

@RequestMapping("/api/products")

public class ProductController {


    @Autowired

    private ProductService productService;


    // Tüm ürünleri döner ve her birine HATEOAS linkleri ekler

    @GetMapping

    public List<EntityModel<ProductDTO>> getAllProducts() {

        List<ProductDTO> products = productService.getAllProducts();

        return products.stream()

                .map(product -> EntityModel.of(product,

                        linkTo(methodOn(ProductController.class).getProductById(product.getId())).withSelfRel(),

                        linkTo(methodOn(ProductController.class).getAllProducts()).withRel("all-products")))

                .collect(Collectors.toList());

    }


    // Belirli bir ürünü döner ve HATEOAS linkleri ekler

    @GetMapping("/{id}")

    public ResponseEntity<EntityModel<ProductDTO>> getProductById(@PathVariable Long id) {

        return productService.getProductById(id)

                .map(productDTO -> {

                    EntityModel<ProductDTO> resource = EntityModel.of(productDTO);

                    // Kaynağa kendi linkini ekleme (self link)

                    Link selfLink = linkTo(methodOn(ProductController.class).getProductById(id)).withSelfRel();

                    // Tüm ürünleri dönen link ekleme

                    Link allProductsLink = linkTo(methodOn(ProductController.class).getAllProducts()).withRel("all-products");

                    resource.add(selfLink, allProductsLink);

                    return ResponseEntity.ok(resource);

                })

                .orElse(ResponseEntity.notFound().build());

    }


    @PostMapping

    public ProductDTO createProduct(@RequestBody ProductDTO productDTO) {

        return productService.createProduct(productDTO);

    }


    @PutMapping("/{id}")

    public ResponseEntity<ProductDTO> updateProduct(@PathVariable Long id, @RequestBody ProductDTO productDetails) {

        try {

            ProductDTO updatedProduct = productService.updateProduct(id, productDetails);

            return ResponseEntity.ok(updatedProduct);

        } catch (RuntimeException e) {

            return ResponseEntity.notFound().build();

        }

    }


    @DeleteMapping("/{id}")

    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {

        try {

            productService.deleteProduct(id);

            return ResponseEntity.noContent().build();

        } catch (RuntimeException e) {

            return ResponseEntity.notFound().build();

        }

    }

}



3. EntityModel Kullanımı


  • EntityModel: Bir kaynağın kendisini (örneğin, bir ProductDTO) ve ilişkili HATEOAS bağlantılarını içerir. Her kaynağa bir veya birden fazla bağlantı ekleyebilirsiniz.
  • linkTo() ve methodOn(): Spring HATEOAS’ta bir kaynağa veya başka bir API'ye bağlantı eklemek için kullanılır.


Örnek:

  • withSelfRel(): Kaynağa kendine ait bir bağlantı ekler.
  • withRel("all-products"): Kaynağa ilişkili başka bir URI (örneğin, tüm ürünler) için bir bağlantı ekler.


4. Yanıt Formatı


API yanıtında HATEOAS kullanıldığında, her kaynağa _links alanı eklenir. Bu alan, kaynağa nasıl erişileceğini gösteren bağlantıları içerir.


Örnek Yanıt:



{

  "id": 1,

  "name": "Laptop",

  "price": 1500.0,

  "_links": {

    "self": {

      "href": "http://localhost:8080/api/products/1"

    },

    "all-products": {

      "href": "http://localhost:8080/api/products"

    }

  }

}



5. HATEOAS ile Hypermedia Tabanlı İlişkiler


Yukarıda gösterildiği gibi, HATEOAS kullanarak bir ürün için:

  • self bağlantısı, kaynağın kendisine doğrudan erişimi sağlar.
  • all-products bağlantısı, tüm ürünlerin listesine erişimi sağlar.


Bu yaklaşım, istemcinin API'nin mevcut durumu hakkında bilgi sahibi olmasını sağlar ve istemciye API ile nasıl etkileşime geçebileceğini gösterir.


6. HATEOAS Bağlantılarının Avantajları

  • Kendi Kendine Belirleme: İstemci, HATEOAS yanıtı ile hangi kaynakların mevcut olduğunu ve hangi işlemlerin yapılabileceğini keşfedebilir.
  • Güvenlik ve Esneklik: Kaynaklar arasında bağlantılar belirlenirken güvenli bir yol sağlanır ve API'ye eklenen yeni kaynaklar ya da işlevler istemci tarafından kolayca kullanılabilir.
  • Bakım Kolaylığı: Kaynaklara doğrudan erişmek yerine HATEOAS bağlantıları kullanmak, API'de yapılan değişikliklerin istemci üzerinde minimum etkisi olmasını sağlar.


7. HATEOAS ile Postman veya Tarayıcı Üzerinden Test Etme


Spring Boot HATEOAS desteğini kullanarak API'nizi geliştirdikten sonra Postman veya tarayıcı üzerinden API çağrılarını test edebilir ve yanıt içinde dönen _links alanı ile diğer kaynaklara nasıl bağlantılar eklendiğini görebilirsiniz.


Özet:


  • HATEOAS ile RESTful API'lerinize hypermedia tabanlı ilişkiler ekleyerek kaynaklar arasında kolayca navigasyon yapılmasını sağlayabilirsiniz.
  • EntityModel kullanarak bir kaynağa ilişkili bağlantılar eklemek mümkündür.
  • Spring HATEOAS sayesinde kaynaklarınız istemciler tarafından daha keşfedilebilir hale gelir ve API'niz daha esnek olur.


Bu yapı, büyük ölçekli projelerde API'nın kullanılabilirliğini ve sürdürülebilirliğini artırır.

32. Pagination ve Sorting

  • Pagination ve Sorting işlemlerini Pageable sınıfını kullanarak gerçekleştirin:
  • 32. Pagination (Sayfalama) ve Sorting (Sıralama)


Büyük veri kümelerini dönerken, pagination (sayfalama) ve sorting (sıralama) işlemleri, performansı artırmak ve istemcilerin daha kolay veri yönetimi yapabilmesi için oldukça önemlidir. Spring Boot, Pageable arayüzünü kullanarak bu işlemleri kolayca gerçekleştirmenizi sağlar. Bu arayüz sayesinde, verileri küçük parçalara bölüp sayfa sayfa gösterebilir ve isteğe bağlı olarak sıralayabilirsiniz.


Aşağıda Pagination ve Sorting işlemlerini nasıl yapacağınızı ve Pageable arayüzünü nasıl kullanacağınızı anlatıyorum.


1. Pageable Nedir?


Pageable, Spring Data JPA tarafından sağlanan bir arayüzdür ve sayfalama ile sıralama işlemlerini gerçekleştirmek için kullanılır. Pageable, kaçıncı sayfanın döneceği, her sayfada kaç kayıt olacağı ve hangi alanlara göre sıralama yapılacağı gibi bilgileri içerir.


2. Pagination ve Sorting İçin Repository


Spring Data JPA, sayfalama ve sıralama işlemlerini doğrudan JpaRepository'nin sağladığı metotlarla destekler. Bu işlemleri gerçekleştirmek için, repository'deki ilgili metotlar, Pageable parametresi alır ve Page sınıfını döner.


Örnek ProductRepository:



import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.data.repository.PagingAndSortingRepository;


public interface ProductRepository extends JpaRepository<Product, Long>, PagingAndSortingRepository<Product, Long> {

}



Bu örnekte, JpaRepository ve PagingAndSortingRepository'yi kullanarak hem CRUD işlemleri hem de sayfalama ve sıralama işlemleri gerçekleştirilebilir.


3. Controller'da Pagination ve Sorting Kullanımı


Aşağıda bir Spring Boot uygulamasında Pagination ve Sorting işlemlerini nasıl yapacağınızı adım adım açıklıyorum. Bu örnekte ürünleri (Product) sayfalama ve sıralama işlemi ile listeleyeceğiz.


ProductController.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.Pageable;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

@RequestMapping("/api/products")

public class ProductController {


    @Autowired

    private ProductRepository productRepository;


    @GetMapping

    public Page<Product> getAllProducts(Pageable pageable) {

        return productRepository.findAll(pageable);

    }

}



4. Pageable Arayüzü


Pageable arayüzü şu bilgileri içerir:

  • pageNumber: Hangi sayfanın döneceğini belirtir (0 tabanlı).
  • pageSize: Her sayfada kaç veri olacağını belirtir.
  • sort: Verinin hangi alanlara göre sıralanacağını belirtir.


Bu arayüz, Spring Boot tarafından otomatik olarak PageRequest sınıfına dönüştürülür. Örneğin, istemciden gelen şu istek:


GET /api/products?page=1&size=10&sort=name,asc



Bu, ikinci sayfada (0 tabanlı olduğu için page=1), her sayfada 10 ürün gösteren ve name alanına göre artan şekilde sıralama yapan bir sayfalama işlemi anlamına gelir.


5. Page Sınıfı ile Sonuçları Döndürme


Spring Data JPA, sayfalama işlemi için Page sınıfını kullanır. Page sınıfı, dönen verilerin yanı sıra sayfalama bilgilerini de içerir:

  • getTotalElements(): Toplam kaç veri olduğunu döner.
  • getTotalPages(): Toplam kaç sayfa olduğunu döner.
  • getContent(): Mevcut sayfadaki verileri döner.
  • hasNext() ve hasPrevious(): Sonraki veya önceki sayfaların olup olmadığını kontrol eder.


6. Sıralama (Sorting)


Sıralama işlemi Pageable ile birlikte yapılabilir. Kullanıcı, belirli bir alanı artan (ascending) veya azalan (descending) şekilde sıralamak istediğinde, bunu URL parametrelerinde belirtebilir.


Örneğin, aşağıdaki URL, ürünleri price alanına göre artan sırayla sıralar:


GET /api/products?sort=price,asc



Eğer sıralamayı birden fazla alan için yapmak istiyorsanız, şu şekilde bir istek gönderebilirsiniz:


GET /api/products?sort=price,desc&sort=name,asc



Bu istek, önce price alanına göre azalan sırayla, ardından name alanına göre artan sırayla sıralama yapar.


7. Pageable ve Sorting Parametrelerini Elle Oluşturma


Eğer manuel olarak Pageable ve Sort objelerini oluşturmak istiyorsanız, PageRequest ve Sort sınıflarını kullanabilirsiniz.


Örnek: Elle Pageable ve Sort Oluşturma



import org.springframework.data.domain.PageRequest;

import org.springframework.data.domain.Sort;


@GetMapping("/custom-pagination")

public Page<Product> getCustomPagedProducts() {

    Pageable pageable = PageRequest.of(0, 5, Sort.by("price").descending());

    return productRepository.findAll(pageable);

}



Bu örnekte, ilk sayfada 5 adet ürün listelenir ve ürünler price alanına göre azalan şekilde sıralanır.


8. Pagination ve Sorting Sonuçlarını JSON Olarak Döndürme


İstek yapıldığında Spring Boot, veriyi Page sınıfı ile döndürür ve bu sonuç JSON formatında şu şekilde olabilir:


Örnek JSON Yanıtı:



{

  "content": [

    {

      "id": 1,

      "name": "Laptop",

      "price": 1500.0

    },

    {

      "id": 2,

      "name": "Tablet",

      "price": 800.0

    }

  ],

  "pageable": {

    "sort": {

      "sorted": true,

      "unsorted": false,

      "empty": false

    },

    "offset": 0,

    "pageNumber": 0,

    "pageSize": 2,

    "paged": true,

    "unpaged": false

  },

  "totalPages": 5,

  "totalElements": 10,

  "last": false,

  "first": true,

  "numberOfElements": 2,

  "size": 2,

  "number": 0,

  "sort": {

    "sorted": true,

    "unsorted": false,

    "empty": false

  },

  "first": true,

  "last": false

}



9. Pageable ile HATEOAS Kullanımı (Opsiyonel)


Spring HATEOAS ile birlikte sayfalama sonuçlarını daha anlamlı hale getirebilirsiniz. Her sayfanın self, next, ve previous bağlantılarını ekleyerek istemcilerin sayfalama navigasyonunu kolaylaştırabilirsiniz.


Örnek:



@GetMapping("/products")

public PagedModel<EntityModel<Product>> getAllProducts(Pageable pageable, PagedResourcesAssembler<Product> assembler) {

    Page<Product> products = productRepository.findAll(pageable);

    return assembler.toModel(products);

}



Bu yapı, sayfalama sonuçlarına HATEOAS bağlantıları ekler. Örneğin, bir sonraki veya önceki sayfaya geçiş için next ve prev bağlantıları döner.


Özet:


  • Pagination ve Sorting, büyük veri kümelerini daha verimli bir şekilde yönetmek için kullanılır.
  • Pageable arayüzü, Spring Data JPA ile sayfalama ve sıralama işlemlerini kolaylaştırır.
  • İstemci, URL parametreleri ile sayfalama ve sıralama işlemlerini yönetebilir.
  • Page sınıfı, sayfalama bilgilerini ve verileri döner, ayrıca toplam sayfa ve kayıt sayısı gibi metrikler sağlar.
  • İsteğe bağlı olarak HATEOAS ile sayfalama sonuçlarına navigasyon bağlantıları eklenebilir.


Bu yapılar sayesinde uygulamanızda veri kümelerini sayfalayarak daha verimli ve yönetilebilir hale getirebilirsiniz.

33. Caching (Önbellekleme)

33. Caching (Önbellekleme) ile Performans İyileştirme


Önbellekleme (Caching), sık kullanılan veya tekrar tekrar sorgulanan verileri bellekte saklayarak performans iyileştirmesi sağlayan bir tekniktir. Veritabanı sorgularını ve işlemleri optimize etmek için kullanılan bu yöntem, Spring Boot’ta @Cacheable gibi anotasyonlarla kolayca uygulanabilir.


Spring Boot’ta @Cacheable, @CachePut, ve @CacheEvict gibi anotasyonlar kullanarak önbelleğe almayı yönetebilirsiniz. @Cacheable, belirli bir veriyi ilk kez alındığında önbelleğe koyar, sonraki isteklerde ise doğrudan bu önbellekten yanıt döner. Bu sayede, veritabanına yapılan sorguların sayısını azaltır ve performans artışı sağlar.


1. Spring Boot’ta Caching Ayarları


Önbellekleme işlemlerini Spring Boot'ta etkinleştirmek için birkaç temel adım gereklidir:


Adım 1: Bağımlılıkları Ekleyin


İlk olarak, Spring Boot Cache Starter bağımlılığını projenize ekleyin. pom.xml dosyanıza şu bağımlılığı ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-cache</artifactId>

</dependency>



Adım 2: Caching Mekanizmasını Etkinleştirin


Spring Boot’ta önbellekleme işlemlerini etkinleştirmek için uygulamanızın ana sınıfına @EnableCaching anotasyonunu ekleyin.


DemoApplication.java



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cache.annotation.EnableCaching;


@SpringBootApplication

@EnableCaching

public class DemoApplication {


    public static void main(String[] args) {

        SpringApplication.run(DemoApplication.class, args);

    }

}



Bu adım, Spring Boot’un önbellekleme altyapısını uygulamanızda etkinleştirir.


2. @Cacheable ile Önbellekleme


Spring Boot'ta @Cacheable anotasyonu, bir metot sonucunu önbelleğe almak için kullanılır. Aşağıdaki örnekte, ürünleri getiren bir metot önbelleğe alınarak sonraki isteklerde önbellekten veri alınması sağlanır.


ProductService.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.stereotype.Service;


import java.util.List;


@Service

public class ProductService {


    @Autowired

    private ProductRepository productRepository;


    // Ürünleri önbelleğe al

    @Cacheable("products")

    public List<Product> getAllProducts() {

        System.out.println("Veritabanından ürünler alınıyor...");

        return productRepository.findAll();

    }


    // Diğer metotlar...

}



Açıklama:

  • @Cacheable("products"): Bu anotasyon, getAllProducts metodunun sonucunu products adlı bir önbelleğe koyar. Eğer bu metot bir kez çalıştırıldıysa, aynı parametrelerle yapılan sonraki çağrılar önbellekten döner ve veritabanı sorgusunu tekrarlamaz.


3. Caching Çalışma Mantığı


@Cacheable anotasyonu, metot çağrıldığında ilk kez veriyi üretir ve önbelleğe koyar. Aynı parametrelerle yapılan sonraki çağrılar önbellekten çekilir ve metot bir daha çalıştırılmaz.


Örneğin, yukarıdaki getAllProducts() metodu ilk çalıştırıldığında veritabanından ürünler alınır ve önbelleğe koyulur. Ancak aynı metot tekrar çağrıldığında, veritabanı yerine önbellekten veri alınır. Bu da veritabanına yapılan gereksiz istekleri azaltır ve performansı artırır.


4. @CacheEvict ile Önbelleği Temizleme


Önbellekte saklanan veriler zamanla güncelliğini yitirebilir. Bu durumda, önbelleği temizlemek için @CacheEvict anotasyonu kullanılır. Örneğin, bir ürünü güncellediğinizde veya sildiğinizde, önbelleğin de güncellenmesi gerekir.


ProductService.java



import org.springframework.cache.annotation.CacheEvict;

import org.springframework.stereotype.Service;


@Service

public class ProductService {


    // Ürün oluşturma işlemi, önbelleği temizler

    @CacheEvict(value = "products", allEntries = true)

    public Product createProduct(Product product) {

        return productRepository.save(product);

    }


    // Ürün silme işlemi, önbelleği temizler

    @CacheEvict(value = "products", allEntries = true)

    public void deleteProduct(Long id) {

        productRepository.deleteById(id);

    }

}



Açıklama:

  • @CacheEvict(value = "products", allEntries = true): Bu anotasyon, ürün oluşturma ve silme işlemlerinden sonra products önbelleğini temizler. allEntries = true parametresi, ilgili tüm önbellek girişlerini siler.


5. @CachePut ile Önbelleği Güncelleme


@CachePut anotasyonu, metot her çağrıldığında sonucu önbelleğe koyar, yani metot çalışmaya devam eder ancak sonucunu da güncellenmiş haliyle önbelleğe ekler. Örneğin, bir ürünü güncellediğinizde önbelleğin de güncellenmesini istiyorsanız @CachePut kullanabilirsiniz.


ProductService.java



import org.springframework.cache.annotation.CachePut;

import org.springframework.stereotype.Service;


@Service

public class ProductService {


    @CachePut(value = "products", key = "#product.id")

    public Product updateProduct(Product product) {

        return productRepository.save(product);

    }

}



Açıklama:

  • @CachePut(value = "products", key = "#product.id")**: Ürün güncellendiğinde, bu metodun sonucunu **products** önbelleğinde günceller. **key = "#product.id" ile hangi ürünün önbelleğinin güncelleneceği belirlenir.


6. Önbellek Sağlayıcıları


Spring Boot, farklı önbellek sağlayıcılarıyla çalışabilir. Bunlar:

  • ConcurrentMapCacheManager: Bellekte basit bir harita kullanarak önbellek oluşturur (varsayılan).
  • EhCache: Popüler bir önbellekleme kütüphanesi.
  • Caffeine: Yüksek performanslı bir Java önbellek kütüphanesi.
  • Redis: Dağıtık önbellek sistemidir, büyük ölçekli projelerde yaygın olarak kullanılır.


7. application.properties ile Caching Yapılandırması


Spring Boot, ConcurrentMapCacheManager kullanarak basit bir bellek içi önbelleği varsayılan olarak sağlar. Ancak projede daha gelişmiş önbellek sağlayıcıları kullanmak istiyorsanız, yapılandırmalarınızı application.properties veya application.yml dosyanızda yapabilirsiniz.


Örnek: EhCache Yapılandırması


EhCache kullanarak önbellekleme yapmak için pom.xml dosyanıza şu bağımlılığı ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-cache</artifactId>

</dependency>

<dependency>

    <groupId>net.sf.ehcache</groupId>

    <artifactId>ehcache</artifactId>

    <version>2.10.6</version>

</dependency>



application.properties dosyasına EhCache ayarlarını ekleyebilirsiniz:



spring.cache.type=ehcache



8. Önbellek için Redis Kullanımı (Opsiyonel)


Redis gibi dağıtık bir önbellekleme sistemi, büyük ölçekli uygulamalarda yaygın olarak kullanılır. Redis, verileri RAM’de tutarak çok hızlı erişim sağlar.


Redis Bağımlılığı Ekleme:


pom.xml dosyasına Redis bağımlılığını ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>



application.properties Yapılandırması:


Redis ile bağlantı kurmak için application.properties dosyasına şu ayarları ekleyin:



spring.cache.type=redis

spring.redis.host=localhost

spring.redis.port=6379



Redis kurulumu yapıldıktan sonra, aynı şekilde @Cacheable, @CachePut, ve @CacheEvict anotasyonlarıyla Redis üzerinde önbellekleme yapabilirsiniz.


34. Internationalization (i18n)

  • Uygulamanızı çoklu dil desteği ile yapılandırın ve yerelleştirilmiş mesajları sağlayın:

  •   messages_en.properties
  •   messages_fr.properties

Spring Boot uygulamalarında Internationalization (i18n), farklı dillerde ve bölgelerde kullanıcıya içerik sunabilmek için kullanılır. Bu özellik sayesinde, uygulamanızın kullanıcı arayüzünü (UI) veya mesajlarını çeşitli dillere ve yerel formatlara göre özelleştirebilirsiniz.


Spring Boot'ta i18n Nasıl Yapılır?


  • messages_*.properties Dosyalarını Oluşturma:
  • Farklı diller için yerelleştirilmiş mesajlar içeren .properties dosyaları oluşturmalısınız. Örneğin:

    • messages_en.properties (İngilizce):

    •      greeting=Hello
    •      goodbye=Goodbye


    • messages_fr.properties (Fransızca):

    •      greeting=Bonjour
    •      goodbye=Au revoir


Bu dosyalar, Spring Boot uygulamanızın kaynaklar klasöründe (src/main/resources) yer almalıdır. Spring Boot, bu dosyalardan uygun dili ve yerel ayarları kullanarak mesajları alır.


  • Spring Boot Konfigürasyonu:
  • Spring Boot'ta, i18n desteği sağlamak için bazı ayarları yapmanız gerekmektedir. Genellikle, bir LocaleResolver tanımlanarak kullanıcıların hangi dili kullanacağını belirlemek mümkündür.

  • Örneğin, application.properties dosyanıza aşağıdaki ayarı ekleyerek varsayılan dilin İngilizce olmasını sağlayabilirsiniz:


  •    spring.messages.basename=messages
  •    spring.messages.locale=en


  • Bu ayar, Spring Boot'un messages_*.properties dosyalarını kullanmasını sağlar.

  • LocaleResolver Yapılandırması:
  • Uygulamanın hangi dili kullanacağını belirlemek için bir LocaleResolver tanımlanmalıdır. AcceptHeaderLocaleResolver kullanarak, tarayıcı isteklerinden gelen "Accept-Language" başlığına göre dili seçebilirsiniz. Bunu şu şekilde yapılandırabilirsiniz:


  •    import org.springframework.context.annotation.Bean;
  •    import org.springframework.context.annotation.Configuration;
  •    import org.springframework.web.servlet.LocaleResolver;
  •    import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
  •    
  •    import java.util.Locale;
  •    
  •    @Configuration
  •    public class LocaleConfig {
  •    
  •        @Bean
  •        public LocaleResolver localeResolver() {
  •            AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
  •            localeResolver.setDefaultLocale(Locale.ENGLISH);
  •            return localeResolver;
  •        }
  •    }


  • Mesajları Kullanma:
  • Yerelleştirilmiş mesajları kullanmak için Spring’in MessageSource ve Locale desteğinden faydalanabilirsiniz. Örneğin, bir kontrolcüde mesajları şu şekilde kullanabilirsiniz:


  •    import org.springframework.beans.factory.annotation.Autowired;
  •    import org.springframework.context.MessageSource;
  •    import org.springframework.web.bind.annotation.GetMapping;
  •    import org.springframework.web.bind.annotation.RequestHeader;
  •    import org.springframework.web.bind.annotation.RestController;
  •    
  •    import java.util.Locale;
  •    
  •    @RestController
  •    public class GreetingController {
  •    
  •        @Autowired
  •        private MessageSource messageSource;
  •    
  •        @GetMapping("/greeting")
  •        public String greeting(@RequestHeader(name = "Accept-Language", required = false) Locale locale) {
  •            return messageSource.getMessage("greeting", null, locale);
  •        }
  •    }


  • Burada, tarayıcıdan gelen "Accept-Language" başlığına göre uygun dilde mesaj görüntülenecektir.


Uygulamanızın Test Edilmesi:

Uygulamanızın çalıştığını test etmek için, tarayıcınızın dil ayarlarını değiştirerek aynı URL’ye farklı dillerde istek gönderebilirsiniz. Eğer her dil için doğru mesaj döndürülüyorsa, i18n işlemi başarıyla tamamlanmıştır.


Örnek i18n Senaryosu:

  • Tarayıcı dili İngilizce ise /greeting isteği "Hello" mesajını dönecektir.
  • Tarayıcı dili Fransızca ise /greeting isteği "Bonjour" mesajını dönecektir.


Bu yöntemle Spring Boot uygulamanızda çoklu dil desteğini kolayca ekleyebilir ve farklı bölgelerden gelen kullanıcılarınıza daha iyi bir deneyim sunabilirsiniz.

35. Spring Boot Banner Özelleştirme

  • Uygulama başlatıldığında görünen banner'ı özelleştirin. banner.txt dosyası ekleyin.

35. Spring Boot Banner Özelleştirme


Spring Boot projeleri başlatıldığında, varsayılan olarak Spring Boot logosu ASCII karakterlerle terminalde gösterilir. Bu banner, projeye özel olarak özelleştirilebilir ve uygulamanızın başlatılması sırasında kendi logonuz veya mesajlarınız terminalde gösterilebilir. Banner'ı özelleştirmek için bir banner.txt dosyası ekleyebilirsiniz.


1. Varsayılan Banner


Spring Boot'un varsayılan banner'ı şu şekildedir:



  .   ____          _            __ _ _

 /\\ / ___'_ __  __ _ _ __ ___  _ _| | '_ \

( ( )\___ | '_ \/ _` | '_/ _ \| '_| | '_(_)

/_/  ____) | | | (_| | | |  __/ | | | |_) |

    |_____|_|  \__,_|_|  \___|_| |_|_.__(_)




2. Özelleştirilmiş Banner Kullanma


Spring Boot, uygulama başlatıldığında gösterilecek olan banner'ı, src/main/resources dizininde banner.txt dosyasında arar. Bu dosyayı oluşturarak kendi ASCII sanatınızı veya mesajınızı ekleyebilirsiniz.


Adım 1: banner.txt Dosyası Oluşturma


Projenizin src/main/resources dizinine banner.txt dosyasını ekleyin.


Örnek: Basit bir banner:



  _____                 _     ____              _   

 |  __ \               | |   |  _ \            | |  

 | |__) |___ _ __   ___ | |_  | |_) |_ __  _   _| |_ 

 |  _  // _ \ '_ \ / _ \| __| |  _ <| '_ \| | | | __|

 | | \ \  __/ | | | (_) | |_  | |_) | | | | |_| | |_ 

 |_|  \_\___|_| |_|\___/ \__| |____/|_| |_|\__,_|\__|

                                                    



Bu örnek, uygulama başlatıldığında terminalde görünecektir. ASCII sanatı oluşturmak için çeşitli çevrimiçi araçları kullanabilirsiniz, örneğin patorjk.com sitesinden çeşitli font seçenekleriyle ASCII banner'ları oluşturabilirsiniz.


Adım 2: Dinamik Bilgi Eklemek


banner.txt dosyasına bazı dinamik bilgileri, yani Spring Boot'tan gelen yerleşik değişkenleri ekleyebilirsiniz. Bu değişkenler uygulama başlatıldığında değerleriyle doldurulur.


Kullanabileceğiniz bazı yerleşik değişkenler:

  • ${application.version}: Projenizin versiyon numarasını ekler.
  • ${application.formatted-version}: Versiyon numarasını formatlar ve ekler.
  • ${spring-boot.version}: Spring Boot sürümünü ekler.
  • ${java.version}: Uygulamanın çalıştığı Java sürümünü ekler.
  • ${os.name}: İşletim sistemi adını ekler.
  • ${user.name}: Kullanıcı adını ekler.


Örneğin:



  _______              _    

 |__   __|            | |   

    | | ___  _ __  ___| |_  

    | |/ _ \| '_ \/ __| __| 

    | | (_) | | | \__ \ |_  

    |_|\___/|_| |_|___/\__| 


 Application Version: ${application.version}

 Java Version: ${java.version}

 Running on: ${os.name}



3. Banner'ı Devre Dışı Bırakma


Eğer banner'ı tamamen devre dışı bırakmak isterseniz, application.properties dosyanıza aşağıdaki ayarı ekleyebilirsiniz:



spring.main.banner-mode=off



Bu ayar, uygulama başlatıldığında herhangi bir banner'ın görüntülenmesini engeller.


4. Banner Modları


Banner'ı farklı şekillerde göstermek için banner-mode ayarını kullanabilirsiniz:

  • console (Varsayılan): Banner terminalde gösterilir.
  • log: Banner sadece log dosyalarında gösterilir.
  • off: Banner tamamen devre dışı bırakılır.


Örnek: Banner'ı sadece log dosyasında göstermek:



spring.main.banner-mode=log



5. Banner Resimlerini Kullanma (Opsiyonel)


banner.txt kullanarak ASCII sanatını özelleştirebileceğiniz gibi, resim dosyalarını da terminalde banner olarak gösterebilirsiniz. Bunun için resminizi banner.jpg veya banner.png olarak src/main/resources dizinine ekleyebilirsiniz. Spring Boot, terminalde ASCII olarak dönüştürülmüş bir görüntüyü gösterecektir.


Örnek: banner.jpg


  • JPG veya PNG formatında bir resim dosyasını src/main/resources/banner.jpg ya da banner.png olarak ekleyin.
  • Uygulama başlatıldığında bu resim ASCII karakterlerle dönüştürülerek gösterilecektir.


Özet:


  • Spring Boot uygulamalarında varsayılan banner'ı özelleştirmek için banner.txt dosyasını kullanabilirsiniz.
  • ASCII sanatını banner.txt'ye ekleyerek, uygulamanız başlatıldığında terminalde istediğiniz logoyu veya mesajı gösterebilirsiniz.
  • Dinamik değişkenlerle (örn. ${java.version}) uygulama hakkında bilgi ekleyebilirsiniz.
  • Banner'ı tamamen kapatabilir veya sadece log dosyasına yazılmasını sağlayabilirsiniz.


Bu özelleştirme, uygulamanızın karakterini yansıtmanıza ve geliştiricilere veya kullanıcıya hoş bir dokunuş eklemenize yardımcı olur.

36. Spring Boot Logging Yapılandırması

  • application.properties dosyasını kullanarak log seviyesini yapılandırın:

  •   logging.level.org.springframework=DEBUG
  •   logging.file.name=app-log.log


37. Interceptors ile HTTP İsteklerini Yakalama

  • HandlerInterceptor sınıfı ile HTTP istekleri arasında davranışlar ekleyin:

  •   public class RequestInterceptor implements HandlerInterceptor {
  •       @Override
  •       public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
  •           // Ön işleme yapılabilir
  •           return true;
  •       }
  •   }

Spring Boot uygulamalarında Interceptors (yakalayıcılar), HTTP isteklerini yakalamak ve bunlar üzerinde belirli işlemler yapmak için kullanılır. Bir interceptör, bir HTTP isteği işleyiciye (controller'a) ulaşmadan önce, işlem sırasında ve sonrasında müdahalede bulunmanıza olanak tanır.


Interceptor ile HTTP İsteklerini Yakalama:


Spring'deki interceptörler, HandlerInterceptor arayüzü ile uygulanır ve üç ana aşamada müdahale edebilir:


  1. preHandle: HTTP isteği işlenmeden önce çalışır. Örneğin, kimlik doğrulama veya isteği loglamak için kullanılabilir.
  2. postHandle: İstek işlendikten sonra ancak yanıt oluşturulmadan önce çalışır. Veriyi değiştirmek veya işleme sonrası ek kontroller yapmak için kullanılabilir.
  3. afterCompletion: Yanıt oluştuktan ve tamamen gönderildikten sonra çalışır. Kaynakları temizlemek veya log işlemlerini tamamlamak için kullanılabilir.


Örnek Interceptor Kullanımı:


  1. Interceptor Sınıfının Yazılması:
  2. HandlerInterceptor arayüzünü implement ederek bir interceptör oluşturabilirsiniz. Örneğin, HTTP isteğini loglayan basit bir interceptör:


  3.    import javax.servlet.http.HttpServletRequest;
  4.    import javax.servlet.http.HttpServletResponse;
  5.    import org.springframework.web.servlet.HandlerInterceptor;
  6.    
  7.    public class RequestInterceptor implements HandlerInterceptor {
  8.        
  9.        // İstek işleyiciye ulaşmadan önce çalışır
  10.        @Override
  11.        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
  12.            System.out.println("İstek URL'i: " + request.getRequestURL());
  13.            return true; // İşleyicinin devam etmesine izin verir
  14.        }
  15.    
  16.        // İşleyici çalıştıktan sonra ama yanıt üretilmeden önce çalışır
  17.        @Override
  18.        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
  19.            System.out.println("İstek işlendikten sonra: " + request.getRequestURL());
  20.        }
  21.    
  22.        // Yanıt tamamen oluşturulup gönderildikten sonra çalışır
  23.        @Override
  24.        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
  25.            System.out.println("Yanıt oluşturuldu ve işlem tamamlandı.");
  26.        }
  27.    }


  28. Interceptor'ın Yapılandırılması:
  29. Interceptor’ı Spring Boot uygulamanıza eklemek için, bir yapılandırma sınıfında WebMvcConfigurer arayüzünü implemente edebilir ve interceptörünüzü kaydedebilirsiniz.


  30.    import org.springframework.context.annotation.Configuration;
  31.    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  32.    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  33.    
  34.    @Configuration
  35.    public class WebConfig implements WebMvcConfigurer {
  36.    
  37.        @Override
  38.        public void addInterceptors(InterceptorRegistry registry) {
  39.            registry.addInterceptor(new RequestInterceptor());
  40.        }
  41.    }


  42. preHandle Yöntemi:
  43. Bu yöntem, isteğin işlenmesinden hemen önce çalıştırılır. Burada kontrol işlemleri yapabilir veya belirli bir duruma göre işleyicinin devam edip etmeyeceğine karar verebilirsiniz. Eğer false döndürürseniz, isteğin işleyiciye ulaşması engellenir.


  44.    @Override
  45.    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
  46.        System.out.println("İstek yakalandı: " + request.getRequestURI());
  47.        // Örneğin yetkilendirme kontrolü yapabilir
  48.        return true; // İşleyiciye geçişe izin ver
  49.    }


  50. postHandle Yöntemi:
  51. İsteğin işlenmesinden sonra, yanıt oluşturulmadan önce çalıştırılır. Bu aşamada işleyici tarafından döndürülen ModelAndView nesnesine erişebilir ve bu veriyi değiştirebilirsiniz.


  52.    @Override
  53.    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
  54.        System.out.println("İstek sonrası işlemler yapılıyor.");
  55.    }


  56. afterCompletion Yöntemi:
  57. İstek ve yanıt tamamen tamamlandıktan sonra çağrılır. Örneğin, bir hata oluştuysa veya işlemin tam anlamıyla bitmesini izlemek için kullanılır.


  58.    @Override
  59.    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
  60.        if (ex != null) {
  61.            System.out.println("Bir hata oluştu: " + ex.getMessage());
  62.        }
  63.        System.out.println("İşlem tamamlandı.");
  64.    }


Interceptor Kullanım Senaryoları:

  • Yetkilendirme ve Kimlik Doğrulama: İsteğin işlenmesinden önce kullanıcı yetkilendirmesi yapmak için kullanılabilir.
  • İstekleri Loglama: Gelen isteklerin loglanması, hata ayıklama ve izleme süreçlerinde faydalıdır.
  • Yanıtların Değiştirilmesi: Yanıtın işlenmeden önce veya sonra bazı ek işlemler yapmak için kullanılabilir.
  • Hata Yönetimi: afterCompletion yöntemiyle hataları yakalayıp yönetebilirsiniz.


Spring Boot ile interceptörler, HTTP isteklerinin işlenme sürecinde büyük esneklik sağlar ve bu sayede uygulamanızın çeşitli aşamalarında kontrol sağlayabilirsiniz.

38. Filtreler (Filters) Kullanımı

  • HTTP istek ve yanıtlarını filtrelemek için javax.servlet.Filter kullanın:

  •   @Component
  •   public class CustomFilter implements Filter {
  •       @Override
  •       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  •           // Filtreleme işlemleri
  •           chain.doFilter(request, response);
  •       }
  •   }

38. Filtreler (Filters) Kullanımı


Spring Boot projelerinde, Servlet Filter kullanarak gelen HTTP istekleri ve yanıtları filtreleyebilirsiniz. Filtreler, bir istek veya yanıt üzerinde manipülasyon yaparak ek güvenlik katmanları eklemek, loglama işlemleri gerçekleştirmek veya istekleri modifiye etmek için kullanılır.


javax.servlet.Filter arayüzü, bir web uygulamasında istekler ve yanıtlar üzerinde işlem yapmak için kullanılan en yaygın araçlardan biridir. Bu filtreler, istemciden gelen istekler işlenmeden önce veya yanıtlar istemciye gitmeden önce devreye girer.


Aşağıda javax.servlet.Filter kullanarak HTTP istek ve yanıtlarını nasıl filtreleyeceğinizi adım adım anlatıyorum.


1. Filtre Nedir?


Filtreler, HTTP istekleri veya yanıtları üzerinde işlem yapmanıza olanak tanıyan ve bu isteklerin servislere iletilmeden önce (pre-processing) veya yanıtların istemciye gitmeden önce (post-processing) değişiklikler yapabilmenizi sağlayan bileşenlerdir.


  • Pre-processing: İstek geldiğinde, bu isteğin işlenip işlenmeyeceğini belirleyebilirsiniz. Örneğin, isteklerin doğruluğunu veya kimlik doğrulama gibi işlemleri burada kontrol edebilirsiniz.
  • Post-processing: Servisin yanıt vermesinden hemen önce, yanıt üzerinde işlemler gerçekleştirebilirsiniz.


2. Filtre Sınıfı Oluşturma


Spring Boot'ta bir filtre oluşturmak için javax.servlet.Filter arayüzünü uygulayan bir sınıf yazmanız gerekir. Filtre sınıfı içinde gelen HTTP istek ve yanıtlarını işleyebilir, gerektiğinde loglama veya güvenlik gibi işlemler gerçekleştirebilirsiniz.


Örnek: CustomFilter.java



import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import org.springframework.stereotype.Component;


import java.io.IOException;


@Component

public class CustomFilter implements Filter {


    @Override

    public void init(FilterConfig filterConfig) throws ServletException {

        // Filtre başlatılırken yapılacak işlemler (isteğe bağlı)

    }


    @Override

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        // İstek işlemleri (Pre-processing)

        System.out.println("CustomFilter: İstek işleniyor.");


        // Filtre zincirine devam etme (diğer filtrelere geç)

        chain.doFilter(request, response);


        // Yanıt işlemleri (Post-processing)

        System.out.println("CustomFilter: Yanıt gönderiliyor.");

    }


    @Override

    public void destroy() {

        // Filtre sonlandırılırken yapılacak işlemler (isteğe bağlı)

    }

}



Açıklamalar:

  • @Component: Bu anotasyon ile filtreyi Spring bileşeni olarak kaydediyoruz. Bu sayede Spring Boot, uygulama başlatıldığında filtreyi otomatik olarak devreye sokacaktır.
  • doFilter: Bu metod, her HTTP isteği veya yanıtı geçtiğinde çalışır. İsteği işleyebilir, gerektiğinde istekleri değiştirebilir veya loglama işlemleri yapabilirsiniz.
    • Pre-processing: İstek işlenmeden önce yapılacak işlemler.
    • Post-processing: Yanıt istemciye gönderilmeden önce yapılacak işlemler.
  • chain.doFilter(request, response): Filtre zincirine devam etme komutudur. Diğer filtreler veya sonrasında gelen işlemler bu metot çağrısından sonra gerçekleşir.


3. Filtrenin Uygulanması


Spring Boot, filtreleri otomatik olarak kaydeder ve HTTP istekleri bu filtrelerden geçer. Filtreler varsayılan olarak tüm URL desenlerine uygulanır.


İsteğe Bağlı: Filtreyi Belirli Bir URL'ye Uygulama


Eğer filtreyi sadece belirli URL desenlerine uygulamak istiyorsanız, FilterRegistrationBean kullanarak bu URL'leri belirleyebilirsiniz.


Örnek: Belirli URL'ler İçin Filtreyi Uygulama



import org.springframework.boot.web.servlet.FilterRegistrationBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;


@Configuration

public class FilterConfig {


    @Bean

    public FilterRegistrationBean<CustomFilter> loggingFilter() {

        FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();


        registrationBean.setFilter(new CustomFilter());

        registrationBean.addUrlPatterns("/api/products/*"); // Sadece bu URL'ler için filtre uygula


        return registrationBean;

    }

}



Bu örnekte, CustomFilter sadece /api/products/* URL desenine sahip istekler için çalıştırılacaktır.


4. FilterChain Nedir?


FilterChain, filtrelerin birbirini takip eden bir zincir halinde çalışmasını sağlar. Her filtre, doFilter() metodu ile zincirde bir sonraki filtreye geçiş yapar. Zincirdeki her filtre bir sonraki işlemi tetikleyebilir veya işlemi sonlandırabilir.


Eğer chain.doFilter(request, response) çağrısını yapmazsanız, zincir durdurulur ve sonrasındaki işlemler gerçekleşmez.


5. Filtre ile HTTP İstek ve Yanıtlarını Manipüle Etme


Filtreler ile gelen HTTP isteklerini değiştirebilir veya yanıtları manipüle edebilirsiniz. Örneğin, bir istek başlığını (header) değiştirebilir ya da yanıt içerik tipini değiştirebilirsiniz.


İstek Başlığını Okuma ve Manipüle Etme:



@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest httpRequest = (HttpServletRequest) request;

    HttpServletResponse httpResponse = (HttpServletResponse) response;


    // İstek başlığını okuma

    String authHeader = httpRequest.getHeader("Authorization");

    System.out.println("Authorization Header: " + authHeader);


    // İstek başlığını manipüle etme (örneğin yeni bir başlık ekleme)

    httpResponse.addHeader("X-Custom-Header", "CustomFilterHeader");


    // Zincire devam et

    chain.doFilter(request, response);

}



6. Filtre Kullanım Senaryoları


Filtreler genellikle şu amaçlarla kullanılır:

  • Güvenlik: Kimlik doğrulama veya yetkilendirme kontrolü (JWT, OAuth, API Key doğrulama).
  • Loglama: Gelen isteklerin ve yanıtların loglanması.
  • Giriş/Çıkış Verilerinin Manipülasyonu: İstek veya yanıt üzerinde özel işlemler gerçekleştirmek.
  • Önbellekleme: İstek yanıtlarını önbellekleme.
  • Veri Sıkıştırma: Yanıt verilerini sıkıştırma veya şifreleme.


7. Spring Security Filtreleri ile Çalışma (Opsiyonel)


Spring Security, filtre tabanlı bir güvenlik mekanizması sağlar. Eğer Spring Security ile çalışıyorsanız, kendi filtrelerinizi Spring Security filtre zincirine dahil edebilir veya mevcut filtreleri özelleştirebilirsiniz. Bu sayede güvenlik filtrelerinin yanında kendi özel filtrelerinizi de kullanabilirsiniz.


Özet:


  • javax.servlet.Filter, Spring Boot'ta gelen ve giden HTTP isteklerini ve yanıtlarını filtrelemek için kullanılır.
  • @Component anotasyonu ile filtreleri Spring bileşeni olarak kaydedebilir ve tüm isteklerde uygulayabilirsiniz.
  • FilterChain, filtrelerin sıralı çalışmasını sağlayan mekanizmadır ve isteklerin bir sonraki aşamaya geçmesi için doFilter() metodu kullanılır.
  • Filtreler, genellikle güvenlik, loglama, istek manipülasyonu gibi işlemlerde kullanılır.
  • Filtreleri belirli URL desenleri için uygulamak istiyorsanız, FilterRegistrationBean ile filtre yapılandırması yapabilirsiniz.


Bu yapılar, Spring Boot uygulamalarında isteklerin ve yanıtların işlenmesinde güçlü ve esnek bir kontrol mekanizması sağlar.

39. Health Checks (Sağlık Kontrolleri)

  • Actuator ile uygulamanızın sağlığını izleyin:

  •   management.endpoint.health.show-details=always


40. Spring Boot Profiles Kullanımı

  • Spring Profiles ile farklı ortamlarda (dev, test, prod) farklı konfigürasyonlar sağlayın:

  •   spring.profiles.active=dev


41. Spring Boot Conditional Beans

  • Farklı profillere göre farklı bean’leri yüklemek için @ConditionalOnProperty gibi anotasyonlar kullanın:

  •   @ConditionalOnProperty(name = "app.feature", havingValue = "true")
  •   @Bean
  •   public MyFeature myFeature() {
  •       return new MyFeature();
  •   }

Spring Boot'ta Conditional Beans özelliği, belirli koşullara göre belirli bean'lerin yüklenip yüklenmeyeceğini kontrol etmenizi sağlar. Bu, uygulamanızın farklı çalışma modlarına veya profillerine göre esneklik kazanmasına olanak tanır. Spring Boot, bu tür koşullu yüklemeler için çeşitli anotasyonlar sunar. Bunlardan biri de @ConditionalOnProperty anotasyonudur.


@ConditionalOnProperty ile Koşullu Bean Tanımlama


@ConditionalOnProperty anotasyonu, bir properties ya da yml dosyasında belirtilen bir özelliğe (property) bağlı olarak bir bean'in yüklenmesini sağlar. Bu, uygulamanızda özelliklerin açılıp kapanmasına izin vererek esnek ve yapılandırılabilir bir davranış sağlar.


Örnek Senaryo:

Bir uygulamada, belirli bir özelliğin (feature) aktif olup olmamasına göre bir bean yüklemek isteyebilirsiniz. Örneğin, "app.feature" adında bir ayar ile bir özelliği açıp kapatmak mümkün olsun.


  1. Uygulama Özelliğini Tanımlama:

  2. application.properties dosyasında özelliği şu şekilde tanımlayabilirsiniz:


  3.    app.feature=true


  4. Ya da application.yml dosyasında:


  5.    app:
  6.      feature: true


  7. Conditional Bean Tanımlama:

  8. @ConditionalOnProperty anotasyonu, belirli bir özelliğin var olup olmadığını kontrol eder ve uygun değeri taşırsa bean oluşturur. Örneğin:


  9.    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  10.    import org.springframework.context.annotation.Bean;
  11.    import org.springframework.context.annotation.Configuration;
  12.    
  13.    @Configuration
  14.    public class MyFeatureConfig {
  15.    
  16.        @ConditionalOnProperty(name = "app.feature", havingValue = "true")
  17.        @Bean
  18.        public MyFeature myFeature() {
  19.            return new MyFeature();
  20.        }
  21.    }


  22. Yukarıdaki örnekte, app.feature özelliği "true" değerine sahipse, MyFeature bean'i Spring konteynerine yüklenecektir. Eğer app.feature=false olarak ayarlanmışsa ya da tanımlanmamışsa, bu bean yüklenmeyecektir.

  23. havingValue Parametresi:
  24. @ConditionalOnProperty'nin en önemli parametrelerinden biri havingValue parametresidir. Bu parametre, özelliğin belirli bir değere sahip olup olmadığını kontrol eder. Eğer havingValue parametresi belirtilmezse, sadece property'sinin varlığı kontrol edilir.


  25.    @ConditionalOnProperty(name = "app.anotherFeature")
  26.    @Bean
  27.    public AnotherFeature anotherFeature() {
  28.        return new AnotherFeature();
  29.    }


  30. Yukarıdaki örnekte, app.anotherFeature özelliği application.properties ya da application.yml dosyasında tanımlıysa, AnotherFeature bean'i yüklenecektir. Özellik tanımlı değilse bean yüklenmez.

  31. Farklı Profillere Göre Bean Yükleme:
  32. Özellikle farklı profillere göre (örneğin dev, prod gibi) bean'lerin yüklenmesini isterseniz, @ConditionalOnProperty veya @Profile anotasyonlarını kullanabilirsiniz. Bununla birlikte, @ConditionalOnProperty ile sadece belirli koşullara göre yükleme yapılabilir.

  33. Örneğin:


  34.    @ConditionalOnProperty(name = "app.feature", havingValue = "true", matchIfMissing = false)
  35.    @Bean
  36.    public MyFeature myFeature() {
  37.        return new MyFeature();
  38.    }


  39. matchIfMissing parametresi, özellik tanımlı değilse bile bean'in yüklenmesini sağlayabilir ya da engelleyebilir. Eğer matchIfMissing=false olarak ayarlanırsa, özellik dosyada tanımlı değilse bean yüklenmez.


Spring Boot'ta Diğer Koşullu Anotasyonlar:

  1. @ConditionalOnMissingBean: Belirli bir bean'in zaten tanımlanmadığı durumlarda yeni bir bean yüklemek için kullanılır.

  2.    @ConditionalOnMissingBean
  3.    @Bean
  4.    public MyService myService() {
  5.        return new MyService();
  6.    }


  7. @ConditionalOnClass: Belirli bir sınıfın classpath'de bulunmasına bağlı olarak bir bean yüklenir.

  8.    @ConditionalOnClass(name = "com.example.SomeClass")
  9.    @Bean
  10.    public SomeFeature someFeature() {
  11.        return new SomeFeature();
  12.    }


  13. @ConditionalOnMissingClass: Belirli bir sınıfın bulunmadığı durumlarda bean yüklenmesini sağlar.


  1. @ConditionalOnBean: Belirli bir bean'in Spring konteynerinde zaten tanımlanmış olması durumunda başka bir bean yüklemek için kullanılır.

  2.    @ConditionalOnBean(name = "someOtherBean")
  3.    @Bean
  4.    public AnotherService anotherService() {
  5.        return new AnotherService();
  6.    }


Sonuç:

@ConditionalOnProperty ve diğer Spring Boot koşullu anotasyonları, uygulamanızı konfigüre edilebilir hale getirir ve sadece gerekli olduğunda belirli bean'lerin yüklenmesini sağlar. Özellikle çok katmanlı ve mikroservis tabanlı uygulamalarda, koşullu bean'lerle sistemi daha dinamik ve yönetilebilir hale getirebilirsiniz.

42. Spring Boot Custom Annotations

  • Kendi anotasyonlarınızı tanımlayın ve tekrar eden davranışları sadeleştirin:

  •   @Target(ElementType.METHOD)
  •   @Retention(RetentionPolicy.RUNTIME)
  •   public @interface LogExecutionTime {
  •   }

42. Spring Boot Custom Annotations (Özel Anotasyonlar)


Spring Boot'ta kendi anotasyonlarınızı tanımlayarak tekrarlayan işlemleri basitleştirebilir ve kodunuzu daha okunabilir hale getirebilirsiniz. Özel anotasyonlar, belirli davranışları sınıflara, metotlara veya alanlara ekleyerek, kodun farklı yerlerinde kullanılan tekrarlı işlevleri soyutlayarak yeniden kullanılabilir hale getirir.


Aşağıda, Spring Boot'ta nasıl özel bir anotasyon tanımlayabileceğinizi ve bu anotasyonla bir metodu sarmalayarak ek işlemler gerçekleştirebileceğinizi gösteriyorum.


1. Özel Bir Anotasyon Tanımlama


Özel bir anotasyon oluşturmak için @interface anahtar kelimesini kullanabilirsiniz. Ayrıca bu anotasyonun hangi elementler üzerinde kullanılacağını ve ne zaman çalışacağını belirtmek için @Target ve @Retention anotasyonlarını kullanmanız gerekir.


Örnek: LogExecutionTime Anotasyonu


Bu örnekte, bir metot çağrıldığında çalıştırılma süresini ölçen bir anotasyon olan @LogExecutionTime'ı tanımlayacağız.



import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;


@Target(ElementType.METHOD) // Anotasyon sadece metodlara uygulanabilir

@Retention(RetentionPolicy.RUNTIME) // Anotasyon çalışma zamanında erişilebilir

public @interface LogExecutionTime {

}



Açıklamalar:

  • @Target(ElementType.METHOD): Bu anotasyonun sadece metotlara uygulanabileceğini belirtir.
  • @Retention(RetentionPolicy.RUNTIME): Bu anotasyonun çalışma zamanında kullanılacağını ve runtime sırasında erişilebileceğini belirtir.


2. Anotasyonu Kullanma


Şimdi, @LogExecutionTime anotasyonunu kullanarak, bir metot çağrıldığında o metodun ne kadar sürede çalıştığını ölçelim. Bunun için Spring’in Aspect-Oriented Programming (AOP) desteğini kullanacağız.


Adım 1: AOP Bağımlılığını Ekleyin


Spring Boot'ta Aspect-Oriented Programming (AOP) kullanarak metot çağrıları öncesinde ve sonrasında işlem yapabilirsiniz. AOP desteği için spring-boot-starter-aop bağımlılığını projenize ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-aop</artifactId>

</dependency>



Adım 2: Aspect Sınıfını Tanımlama


Özel anotasyonumuzu kullanarak metotların çalışma süresini ölçmek için bir Aspect sınıfı oluşturacağız. Bu sınıf, @LogExecutionTime anotasyonunu taşıyan metotları yakalayacak ve bu metotların çalışma süresini loglayacaktır.


LoggingAspect.java



import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;


@Aspect

@Component

public class LoggingAspect {


    @Around("@annotation(LogExecutionTime)")  // @LogExecutionTime anotasyonu taşıyan metotlara uygula

    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

        long start = System.currentTimeMillis();


        Object proceed = joinPoint.proceed();  // Metodu çalıştır


        long executionTime = System.currentTimeMillis() - start;

        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");


        return proceed;

    }

}



Açıklamalar:

  • @Aspect: Bu sınıfın bir Aspect olduğunu belirtir. Aspect sınıfları, belirli bir davranışı programın farklı yerlerinde (metotlar, sınıflar vb.) kesip ek işlemler gerçekleştirir.
  • @Around: Metodun çalıştırılmasından önce ve sonra işlem yapılmasını sağlar. @annotation(LogExecutionTime) ifadesi, sadece @LogExecutionTime anotasyonu ile işaretlenmiş metotlarda bu işlemin yapılacağını belirtir.
  • ProceedingJoinPoint: Metodun kendisini ifade eder. proceed() metodu ile asıl metodun çalıştırılması sağlanır.


3. Anotasyonu Kullanma


Şimdi, @LogExecutionTime anotasyonunu kullanarak bir serviste belirli metotların çalışma süresini ölçelim.


Örnek: ProductService.java



import org.springframework.stereotype.Service;


@Service

public class ProductService {


    @LogExecutionTime

    public void serve() throws InterruptedException {

        // Örnek olarak, işlemi yavaşlatmak için bir gecikme ekleyelim

        Thread.sleep(2000);

    }

}



Bu örnekte, serve metodu her çağrıldığında @LogExecutionTime anotasyonu devreye girer ve metodun ne kadar sürede çalıştığını terminale yazar.


4. Uygulama Çıktısı


Uygulamanızda serve() metodunu çalıştırdığınızda aşağıdaki gibi bir çıktı alabilirsiniz:



public void com.example.ProductService.serve() executed in 2005ms



Bu çıktı, serve() metodunun kaç milisaniyede çalıştığını gösterir.


5. Farklı Anotasyonlar ve Kullanım Alanları


Özel anotasyonlar sadece loglama için değil, aynı zamanda:

  • Kimlik doğrulama ve yetkilendirme işlemlerini kontrol etmek için,
  • Veri doğrulama işlemlerini basitleştirmek için,
  • Cache (Önbellekleme) işlemlerini özelleştirmek için,
  • Performans ölçümü gibi işlemler için de kullanılabilir.


6. Birden Fazla Anotasyon Parametresi ile Çalışma


Anotasyonlara parametre ekleyerek daha fazla kontrol sağlayabilirsiniz. Örneğin, aşağıda @CustomLog adında parametre alan bir anotasyon oluşturalım:


Örnek: CustomLog.java



import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;


@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface CustomLog {

    String message() default "Method executed";

}



Bu anotasyon, bir metot çalıştırıldığında bir log mesajı basmak için kullanılabilir.


LoggingAspect.java



@Around("@annotation(customLog)")

public Object logCustomMessage(ProceedingJoinPoint joinPoint, CustomLog customLog) throws Throwable {

    System.out.println(customLog.message());  // Anotasyonun parametresi olan message'i logla

    return joinPoint.proceed();  // Metodu çalıştır

}



ProductService.java



@CustomLog(message = "Özel log mesajı ile bu metot çalıştırıldı.")

public void customServe() {

    // Metodun içi

}



Bu örnekte, customServe metodu çalıştırıldığında belirtilen özel mesaj loglanacaktır.


Özet:


  • Özel anotasyonlar, tekrarlayan davranışları sadeleştirmek ve kodu daha modüler hale getirmek için kullanılabilir.
  • @LogExecutionTime gibi bir anotasyon tanımlayarak metotların çalışma sürelerini ölçebilir ve AOP ile bu işlemleri yönetebilirsiniz.
  • Anotasyonları AOP ile birlikte kullanarak uygulamanızın çeşitli yerlerinde çapraz kesen (cross-cutting) işlemleri kolayca uygulayabilirsiniz.


Bu yapılar, Spring Boot projelerinde tekrarlı işleri otomatikleştirmenizi ve kodunuzu daha temiz hale getirmenizi sağlar.

43. Spring Cloud Config ile Merkezi Konfigürasyon Yönetimi

  • Spring Cloud Config Server kullanarak merkezi konfigürasyon sağlayın ve uygulamalarınızın konfigürasyonlarını tek bir yerden yönetin.

Spring Cloud Config, merkezi konfigürasyon yönetimi sağlayarak, dağıtık sistemler veya mikroservis mimarilerinde kullanılan uygulamaların yapılandırmalarını tek bir yerden yönetmenize olanak tanır. Bu sayede, farklı ortamlarda (development, production, staging vb.) çalışan uygulamaların konfigürasyonlarını merkezi bir sunucu aracılığıyla yönetebilir, güncellemeleri anında yapabilirsiniz.


Spring Cloud Config Server ile Merkezi Konfigürasyon Yönetimi


1. Spring Cloud Config Server Oluşturma

Spring Cloud Config Server, merkezi bir yapılandırma sunucusu olarak görev yapar ve konfigürasyon dosyalarını bir kaynaktan (Git, SVN, dosya sistemi gibi) alır ve istemcilere (uygulamalara) sunar.


Adım 1: Config Server Projesi Oluşturma

İlk olarak, bir Spring Boot projesi oluşturun ve pom.xml veya build.gradle dosyanıza gerekli bağımlılıkları ekleyin:


Maven:


<dependencies>

    <dependency>

        <groupId>org.springframework.cloud</groupId>

        <artifactId>spring-cloud-config-server</artifactId>

    </dependency>

</dependencies>



Gradle:


implementation 'org.springframework.cloud:spring-cloud-config-server'



Adım 2: Config Server Yapılandırması

Spring Cloud Config Server'ı başlatmak için @EnableConfigServer anotasyonunu kullanın ve sunucunun çalışacağı application.properties veya application.yml dosyasını yapılandırın.


ConfigServerApplication.java:


import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.config.server.EnableConfigServer;


@SpringBootApplication

@EnableConfigServer

public class ConfigServerApplication {

    public static void main(String[] args) {

        SpringApplication.run(ConfigServerApplication.class, args);

    }

}



application.properties (Config Server):


server.port=8888

spring.cloud.config.server.git.uri=https://github.com/kullaniciAdi/repo-adi



Bu örnekte, GitHub üzerinde yer alan bir Git deposundan konfigürasyon dosyaları alınacaktır. spring.cloud.config.server.git.uri ile merkezi konfigürasyon dosyalarının yer aldığı depo belirtilir. Git yerine yerel dosya sistemi veya başka bir kaynak da kullanılabilir.


2. Config Client Oluşturma

Spring Cloud Config Server'dan yapılandırma bilgilerini alacak olan istemci uygulamayı yapılandıralım. Config Client, Spring Boot uygulaması olarak çalışacak ve Config Server'dan gerekli ayarları alacaktır.


Adım 1: Config Client Projesi Oluşturma

Config Client için bir Spring Boot projesi oluşturun ve gerekli bağımlılığı ekleyin.


Maven:


<dependencies>

    <dependency>

        <groupId>org.springframework.cloud</groupId>

        <artifactId>spring-cloud-starter-config</artifactId>

    </dependency>

</dependencies>



Gradle:


implementation 'org.springframework.cloud:spring-cloud-starter-config'



Adım 2: Config Client Yapılandırması

Config Client, application.properties veya application.yml dosyasında Config Server'a nasıl bağlanacağını tanımlar. Aşağıdaki ayarlar, Config Server'ı kullanarak merkezi konfigürasyonu nasıl çekeceğinizi gösterir.


application.properties (Config Client):


spring.application.name=my-application

spring.cloud.config.uri=http://localhost:8888



  • spring.application.name: Bu, Config Server'da bu uygulamaya ait konfigürasyon dosyasının adını temsil eder. Örneğin, Config Server'da my-application.properties veya my-application.yml dosyasına göre ayarlar çekilecektir.
  • spring.cloud.config.uri: Config Server'ın URL'sini belirtir.


Adım 3: Config Dosyalarının Depolanması

Config Server, spring.application.name ile belirtilen uygulamaya uygun dosyaları arar. Örneğin, GitHub'da depoladığınız konfigürasyon dosyaları şu şekilde olabilir:



Dosyaların içeriği şu şekilde olabilir:


my-application.properties:


message=Hello from default configuration!



my-application-dev.properties:


message=Hello from development configuration!



Adım 4: İstemci Uygulamada Config Değerlerini Kullanma

Spring Boot uygulamasında, merkezi konfigürasyon dosyalarından gelen değerleri kullanabilirsiniz.


MyController.java:


import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class MyController {


    @Value("${message}")

    private String message;


    @GetMapping("/message")

    public String getMessage() {

        return message;

    }

}



Bu controller, Config Server'dan gelen message property'sini çekip HTTP isteğiyle geri döner.


3. Config Server ve Client Uygulamalarının Test Edilmesi


  • Config Server'ı başlatın: ConfigServerApplication'ı çalıştırarak Config Server'ın ayakta olduğundan emin olun.
  • Config Client'ı başlatın: MyApplication'ı çalıştırın. Uygulama başlatıldığında Config Server'a bağlanacak ve gerekli konfigürasyonları çekecektir.


Varsayılan ortamda (örneğin development), aşağıdaki URL'ye bir GET isteği yaparak ayarı görebilirsiniz:



http://localhost:8080/message



4. Farklı Profillere Göre Konfigürasyon Yönetimi

Spring Cloud Config, farklı profillere göre (örneğin dev, prod) konfigürasyon dosyalarını yönetir. application.properties veya application.yml dosyalarınıza şu şekilde profil ekleyebilirsiniz:



spring.profiles.active=dev



Bu ayar, Config Client'ın my-application-dev.properties dosyasını kullanmasını sağlar.


Sonuç:

Spring Cloud Config ile merkezi bir konfigürasyon yönetimi kurarak, tüm mikroservislerinizin yapılandırmalarını tek bir yerden yönetebilir, güncellemeleri kolayca uygulayabilirsiniz. Bu, özellikle dağıtık sistemlerde konfigürasyon yönetimini daha ölçeklenebilir ve yönetilebilir hale getirir.

44. Hystrix ile Circuit Breaker

  • Hystrix kullanarak Circuit Breaker desenini uygulayın:

  •   @HystrixCommand(fallbackMethod = "fallbackMethod")
  •   public String callRemoteService() {
  •       return restTemplate.getForObject("http://remote-service/api", String.class);
  •   }
  •   
  •   public String fallbackMethod() {
  •       return "Fallback response";
  •   }


45. Feign Client Kullanımı

  • Rest API'leri çağırmak için Feign Client kullanın:

  •   @FeignClient(name = "product-service", url = "http://localhost:8081")
  •   public interface ProductClient {
  •       @GetMapping("/products")
  •       List<Product> getAllProducts();
  •   }

45. Feign Client Kullanımı


Feign Client, Spring Boot projelerinde RESTful API’lere kolayca HTTP çağrıları yapmak için kullanılan bir araçtır. Feign Client, diğer servislerle iletişim kurmak için HTTP isteklerini daha sade ve temiz bir şekilde yazmanıza olanak tanır. Özellikle mikroservis mimarisinde, servisler arası iletişim için yaygın olarak kullanılır.


Feign Client, basit bir arayüz üzerinden HTTP isteklerini gerçekleştirebilir ve Spring Cloud ile entegrasyonu sayesinde yük dengeleme, hata toleransı gibi özellikler sunar.


1. Feign Client Nedir?


Feign Client, diğer API'lerle iletişim kurmayı kolaylaştıran bir HTTP istemcisidir. Feign, RESTful API çağrılarını kolaylaştırmak için arayüz bazlı bir yaklaşım sunar. HTTP istekleri doğrudan Feign Client arayüzü üzerinden yapılır ve bu işlemler sınıf üzerinde herhangi bir mantık yazmadan yapılabilir.


2. Feign Client Yapılandırması


Spring Boot ile Feign Client kullanmak için bazı adımlar gereklidir. Aşağıda adım adım nasıl yapılandırılacağını anlatıyorum.


Adım 1: Feign Bağımlılığını Ekleyin


İlk olarak spring-cloud-starter-openfeign bağımlılığını pom.xml dosyanıza ekleyin.



<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-openfeign</artifactId>

</dependency>



Adım 2: Feign Desteğini Etkinleştirin


Feign Client desteğini etkinleştirmek için uygulamanızın ana sınıfına @EnableFeignClients anotasyonunu ekleyin.


DemoApplication.java



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.openfeign.EnableFeignClients;


@SpringBootApplication

@EnableFeignClients  // Feign Client desteğini etkinleştirir

public class DemoApplication {


    public static void main(String[] args) {

        SpringApplication.run(DemoApplication.class, args);

    }

}



Adım 3: Feign Client Arayüzü Oluşturma


Feign Client, API çağrılarını gerçekleştirmek için bir arayüz tanımlamanıza olanak tanır. Bu arayüz, çağrılacak servislerin endpoint'lerini ve HTTP metotlarını içerir.


Aşağıdaki örnekte, ProductClient adında bir Feign Client tanımlanmış ve başka bir servisin ürünleri dönen endpoint'ine istek yapılmıştır.


ProductClient.java



import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;


@FeignClient(name = "product-service", url = "http://localhost:8081")  // Servis URL'si

public interface ProductClient {


    @GetMapping("/products")  // /products endpoint'ini çağır

    List<Product> getAllProducts();

}



Açıklamalar:

  • @FeignClient: Bu anotasyon, Feign Client arayüzünü belirtir. name parametresi, çağrılacak servisin adını belirtir. url parametresi, bu servis için kullanılacak URL'yi belirtir.
  • @GetMapping("/products"): Bu metot, ürünleri listeleyen bir GET isteği yapar. Feign Client, HTTP isteğini otomatik olarak oluşturur ve API’ye gönderir.


3. Feign Client Kullanımı


Feign Client arayüzü oluşturulduktan sonra, bu arayüzü servis sınıfınızda kullanabilirsiniz. Spring Boot, ProductClient arayüzünü otomatik olarak inject edebileceğiniz bir Bean olarak sağlayacaktır.


ProductService.java



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.List;


@Service

public class ProductService {


    @Autowired

    private ProductClient productClient;


    public List<Product> getAllProducts() {

        return productClient.getAllProducts();  // Feign Client ile ürünleri al

    }

}



Açıklama:

  • ProductClient: Feign Client'ı ProductService içinde inject ederek, API'yi çağırabilirsiniz. getAllProducts() metodu çalıştığında Feign Client, http://localhost:8081/products URL'sine bir GET isteği gönderir ve sonuç olarak List<Product> döner.


4. Feign Client ile Parametre Kullanımı


Feign Client kullanarak parametreli istekler de yapabilirsiniz. Parametreler hem PathVariable hem de RequestParam şeklinde desteklenir.


Örnek: PathVariable Kullanımı


Eğer bir ürün ID’si ile API çağrısı yapmak isterseniz, PathVariable kullanarak bunu gerçekleştirebilirsiniz.



@FeignClient(name = "product-service", url = "http://localhost:8081")

public interface ProductClient {


    @GetMapping("/products/{id}")

    Product getProductById(@PathVariable("id") Long id);

}



Örnek: RequestParam Kullanımı


Bir istekte RequestParam kullanarak filtreleme veya sıralama gibi işlemler yapabilirsiniz.



@FeignClient(name = "product-service", url = "http://localhost:8081")

public interface ProductClient {


    @GetMapping("/products")

    List<Product> getProducts(@RequestParam("sort") String sort);

}



5. Feign Client Hata Yönetimi


Feign Client kullanırken API çağrıları sırasında hata yönetimi de önemlidir. Feign, belirli HTTP hata durumları ile karşılaştığında uygun yanıtlar döner. Ancak, daha gelişmiş hata yönetimi yapmak için Feign Error Decoder kullanabilirsiniz.


Örnek: Özel Hata Yönetimi


Özel hata yönetimi yapmak için ErrorDecoder sınıfını kullanabilirsiniz.


CustomErrorDecoder.java



import feign.Response;

import feign.codec.ErrorDecoder;

import org.springframework.stereotype.Component;


@Component

public class CustomErrorDecoder implements ErrorDecoder {


    @Override

    public Exception decode(String methodKey, Response response) {

        if (response.status() == 404) {

            return new ProductNotFoundException("Product not found");

        }

        return new Exception("General error");

    }

}



Bu örnekte, API çağrısı sırasında 404 Not Found hatası alındığında özel bir hata ProductNotFoundException fırlatılır.


6. Feign Client ve Eureka Kullanımı (Opsiyonel)


Eğer uygulamanız Spring Cloud Netflix Eureka kullanıyorsa, Feign Client, servis keşfi için Eureka ile entegre edilebilir. Bu sayede, servisin URL'sini sabit olarak vermek yerine, servis ismine göre otomatik olarak adresini bulabilir.


Örnek: Eureka ile Feign Client


Eureka kullanarak Feign Client tanımlarken url parametresi yerine sadece name parametresini belirtebilirsiniz:



@FeignClient(name = "product-service")

public interface ProductClient {


    @GetMapping("/products")

    List<Product> getAllProducts();

}



Bu şekilde, product-service servisi Eureka'da kayıtlı olduğunda Feign Client, Eureka üzerinden servisin adresini otomatik olarak bulur ve ona göre API çağrısı yapar.


7. Feign Client ile Yük Dengeleme


Feign Client, Spring Cloud Netflix Ribbon ile entegre çalışarak yük dengeleme yapabilir. Eğer aynı servisin birden fazla instance'ı varsa, Feign Client bu instance'lar arasında istekleri dengeli bir şekilde dağıtır. Yük dengeleme ayarları Spring Cloud tarafından otomatik olarak yapılır.


8. Feign Client ile OAuth2 ve JWT Entegrasyonu (Opsiyonel)


Feign Client ile güvenli API'lere erişmek için OAuth2 veya JWT kullanabilirsiniz. Feign isteklerine kimlik doğrulama token'ı ekleyerek güvenli bir şekilde REST API'lerini çağırabilirsiniz.


Özet:


  • Feign Client, RESTful API'leri basit arayüzlerle çağırmak için kullanılan güçlü bir araçtır.
  • Spring Boot ile @FeignClient anotasyonu kullanarak kolayca HTTP çağrıları yapabilirsiniz.
  • Feign Client ile parametreli istekler, hata yönetimi ve hatta Eureka gibi servis keşfi araçları ile entegre olabilirsiniz.
  • Feign, kodunuzu sadeleştirerek mikroservisler arasında daha temiz ve düzenli iletişim sağlar.


Bu yapı, özellikle mikroservis tabanlı projelerde, servisler arası iletişimi yönetmek için idealdir.

46. Spring Boot REST API Güvenliği

  • OAuth2 veya JWT kullanarak REST API'lerinizi güvenli hale getirin.


47. Rate Limiting ile Trafiği Yönetme

  • Spring Boot uygulamanızda Rate Limiting uygulayarak istemcilerin belirli bir zaman aralığında yapabilecekleri istek sayısını sınırlayın.

Rate Limiting (istek sınırlaması), bir sistemin belirli bir zaman diliminde ne kadar trafik kabul edeceğini sınırlamak için kullanılan bir tekniktir. Rate Limiting ile istemcilerin aşırı trafik oluşturmasını engelleyebilir ve kaynakların adil bir şekilde dağıtılmasını sağlayabilirsiniz. Spring Boot uygulamanızda Rate Limiting'i uygulamak için çeşitli yaklaşımlar kullanılabilir. Popüler bir yöntem, Spring AOP veya Spring Cloud Gateway ile birlikte Bucket4j gibi rate limiting kütüphanelerinin kullanılmasıdır.


1. Rate Limiting Uygulama Yöntemleri

Spring Boot'ta Rate Limiting'i uygulamak için farklı yaklaşımlar kullanabilirsiniz. Aşağıda popüler yöntemlerden bazıları açıklanmıştır:


1.1. Bucket4j ile Rate Limiting

Bucket4j, token bucket algoritmasını kullanan bir rate limiting kütüphanesidir ve Spring Boot uygulamalarında basit bir şekilde kullanılabilir.


Adım 1: Bucket4j Bağımlılığını Ekleyin

Projenize Bucket4j bağımlılığını ekleyin.


Maven:


<dependency>

    <groupId>com.github.vladimir-bukhtoyarov</groupId>

    <artifactId>bucket4j-core</artifactId>

    <version>7.6.0</version>

</dependency>



Gradle:


implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'



Adım 2: Rate Limiting Yapılandırması

Spring Boot'ta Bucket4j ile rate limiting'i kullanmak için bir servis sınıfı oluşturun ve token bucket algoritmasını uygulayın.



import io.github.bucket4j.Bandwidth;

import io.github.bucket4j.Bucket;

import io.github.bucket4j.Refill;

import org.springframework.stereotype.Service;


import java.time.Duration;


@Service

public class RateLimitService {


    private final Bucket bucket;


    public RateLimitService() {

        // Her dakika 10 token yenileme ile 10 token'lık bir kova oluştur

        Bandwidth limit = Bandwidth.classic(10, Refill.greedy(10, Duration.ofMinutes(1)));

        this.bucket = Bucket.builder().addLimit(limit).build();

    }


    public boolean tryConsume() {

        return bucket.tryConsume(1); // Her istek için 1 token tüket

    }

}



Adım 3: Rate Limiting Kontrolü İçin Bir Endpoint Tanımlama

Kontrolcü (controller) sınıfınıza rate limiting'i entegre edin ve istemcilerin belirli bir zaman aralığında yapabilecekleri istek sayısını sınırlayın.



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class MyController {


    @Autowired

    private RateLimitService rateLimitService;


    @GetMapping("/limited-endpoint")

    public ResponseEntity<String> limitedEndpoint() {

        if (rateLimitService.tryConsume()) {

            return ResponseEntity.ok("Request successful!");

        } else {

            return ResponseEntity.status(429).body("Too many requests - try again later.");

        }

    }

}



Bu örnekte, eğer bir kullanıcının kovasında yeterli token varsa, istek başarıyla işlenir. Aksi takdirde, HTTP 429 (Too Many Requests) yanıtı döner.


1.2. Spring Cloud Gateway ile Rate Limiting

Spring Cloud Gateway, mikroservis mimarilerinde API Gateway olarak kullanılabilir ve istekleri yönetmek için rate limiting gibi politikalar uygulanabilir.


Adım 1: Spring Cloud Gateway Bağımlılığını Ekleyin

Spring Cloud Gateway ve Redis ile rate limiting yapmak için gerekli bağımlılıkları ekleyin.


Maven:


<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-gateway</artifactId>

</dependency>


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>

</dependency>



Gradle:


implementation 'org.springframework.cloud:spring-cloud-starter-gateway'

implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'



Adım 2: Redis Kurulumu

Rate Limiting işlevi için Redis veritabanını kullanabilirsiniz. Redis, istek sayısını takip etmek için iyi bir seçenektir çünkü çok hızlıdır ve verileri hafızada tutar.


Adım 3: Rate Limiting Yapılandırması

application.yml dosyanızda rate limiting yapılandırması yapın.



spring:

  cloud:

    gateway:

      routes:

        - id: my_route

          uri: http://localhost:8080

          predicates:

            - Path=/limited-endpoint/**

          filters:

            - name: RequestRateLimiter

              args:

                redis-rate-limiter.replenishRate: 10  # Saniyede 10 istek

                redis-rate-limiter.burstCapacity: 20  # Maksimum 20 istek biriktirilebilir

                key-resolver: '#{new org.springframework.cloud.gateway.filter.ratelimit.PrincipalNameKeyResolver()}'



Bu yapılandırma, Spring Cloud Gateway üzerinden her saniyede 10 isteğe izin verir ve en fazla 20 isteği aynı anda biriktirebilir.


1.3. Spring AOP ile Rate Limiting

Spring AOP (Aspect-Oriented Programming), çapraz kesen endişeleri (cross-cutting concerns) yönetmek için kullanılır ve istek sınırlaması gibi görevleri belirli methodlar veya endpoint'ler için uygulayabilirsiniz.


Adım 1: AOP Bağımlılığını Ekleyin

Spring AOP'yi projenize ekleyin.


Maven:


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-aop</artifactId>

</dependency>



Gradle:


implementation 'org.springframework.boot:spring-boot-starter-aop'



Adım 2: AOP İle Rate Limiting Kodu

Bir rate limiting aspec’i oluşturun ve belirli methodlar için istek sınırlaması uygulayın.



import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;


@Aspect

@Component

public class RateLimitingAspect {


    @Autowired

    private RateLimitService rateLimitService;


    @Before("execution(* com.example.MyController.*(..))")

    public void checkRateLimit() throws Exception {

        if (!rateLimitService.tryConsume()) {

            throw new Exception("Too many requests");

        }

    }

}



Bu yöntem, belirli methodlar için bir rate limiting kontrolü uygulayarak istekleri sınırlayacaktır.


2. Sonuç

Spring Boot uygulamalarında Rate Limiting, sistem kaynaklarını korumak, hizmetin sürekliliğini sağlamak ve aşırı yüklenmeyi önlemek için kritik bir tekniktir. Bucket4j, Spring Cloud Gateway veya AOP kullanarak Rate Limiting'i kolayca entegre edebilir ve sisteminize göre özelleştirebilirsiniz.

48. Database Migration ile Flyway Kullanımı

  • Flyway kullanarak veri tabanı migrasyonlarını yönetin. SQL dosyalarını src/main/resources/db/migration altına ekleyin.

48. Database Migration ile Flyway Kullanımı


Flyway, Spring Boot projelerinde veri tabanı migrasyonlarını yönetmek için kullanılan popüler bir araçtır. Flyway, uygulamanın veri tabanı şemasını versiyonlayarak farklı ortamlarda tutarlılık sağlar ve veri tabanı değişikliklerini yönetmeyi kolaylaştırır.


Adım Adım Flyway Kullanımı


  1. Flyway Bağımlılığını Ekleyin:
  2. Spring Boot projenizde Flyway kullanmak için pom.xml dosyasına Flyway bağımlılığını eklemeniz gerekir. Maven kullandığınızı varsayarsak:


  3.    <dependency>
  4.        <groupId>org.flywaydb</groupId>
  5.        <artifactId>flyway-core</artifactId>
  6.    </dependency>


  7. Eğer Gradle kullanıyorsanız, build.gradle dosyasına şu satırı ekleyin:


  8.    implementation 'org.flywaydb:flyway-core'


  9. Migration (Geçiş) Dosyalarını Oluşturun:
  10. Flyway, veri tabanı geçiş dosyalarını otomatik olarak algılar ve uygular. Bu dosyaları src/main/resources/db/migration dizinine eklemelisiniz. Flyway, dosyaların isimlendirilmesini takip ederek bu dosyaları sırayla çalıştırır.

  11. Dosya isimlendirme kuralları:
    • Dosyalar şu formatta olmalıdır: V<Versiyon>__<Açıklama>.sql
    • Örnek: V1__Initial_Setup.sql


Bu dosya, veri tabanı şemasının ilk kurulumu için gerekli SQL komutlarını içerebilir. Örneğin:



   CREATE TABLE users (

       id SERIAL PRIMARY KEY,

       username VARCHAR(50) NOT NULL,

       email VARCHAR(100) NOT NULL

   );



  1. Veritabanı Ayarlarını Yapılandırın:
  2. application.properties veya application.yml dosyanızda veri tabanı bağlantısı ayarlarını yapmanız gerekir. Örneğin, bir PostgreSQL veritabanı kullanıyorsanız:


  3.    spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase
  4.    spring.datasource.username=myuser
  5.    spring.datasource.password=mypassword
  6.    spring.datasource.driver-class-name=org.postgresql.Driver
  7.    spring.flyway.enabled=true


  8. Veritabanı Geçişlerini Çalıştırın:
  9. Uygulamanız çalıştığında, Flyway src/main/resources/db/migration dizininde yer alan dosyaları tarar ve henüz çalıştırılmamış olan SQL dosyalarını uygular. Flyway, uygulanan migrasyonları veri tabanında flyway_schema_history adında bir tablo oluşturarak takip eder. Bu tablo, hangi migrasyon dosyalarının uygulandığını ve hangi versiyonda olduğunu kaydeder.


  1. Yeni Migrasyonlar Eklemek:
  2. Eğer veri tabanı şemanızda daha sonra değişiklik yapmak isterseniz, yeni bir SQL dosyası oluşturup src/main/resources/db/migration dizinine eklemeniz yeterlidir. Örneğin, bir tabloya yeni bir sütun eklemek için:


  3.    -- V2__Add_Age_To_Users.sql
  4.    ALTER TABLE users ADD age INT;


  5. Uygulama yeniden başlatıldığında, Flyway bu dosyayı algılayıp sıralı bir şekilde uygulayacaktır.


Flyway İle İlgili Diğer Özellikler:

  • Rollback (Geri Alma): Flyway varsayılan olarak rollback desteği sunmaz. Ancak, undo migrasyon dosyaları oluşturmak mümkündür (Flyway Teams Edition'da).
  • Repeatable Migrations: R__<Açıklama>.sql şeklinde adlandırılan dosyalar tekrar tekrar çalıştırılabilir migrasyonlardır. Örneğin, R__Update_Views.sql dosyası her Flyway çalıştırıldığında tekrar uygulanacaktır.


Flyway, Spring Boot projelerinde veri tabanı değişikliklerini izlemek ve yönetmek için son derece güçlü ve kullanışlı bir araçtır.

49. Liquibase Kullanımı

  • Alternatif olarak Liquibase kullanarak veri tabanı şemasını yönetebilirsiniz.

49. Liquibase Kullanımı


Liquibase, veri tabanı şemasını yönetmek ve sürüm kontrolüne almak için kullanılan popüler bir database migration (veritabanı göçü) aracıdır. Liquibase, veritabanı değişikliklerini izlemek, uygulamak ve geri almak için SQL veya XML, YAML gibi formatlarda changelog dosyaları kullanır. Bu araç, veritabanı yapılarındaki değişiklikleri birden fazla ortamda tutarlı ve güvenli bir şekilde yönetmenizi sağlar.


Spring Boot projelerinde Liquibase, veritabanı şemalarını otomatik olarak yönetmek için kullanılabilir. Aşağıda, Liquibase'i Spring Boot ile nasıl entegre edebileceğinizi ve nasıl kullanabileceğinizi adım adım anlatıyorum.


1. Liquibase Nedir?


Liquibase, veritabanı değişikliklerini izlemek ve uygulamak için kullanılan bir araçtır. Changelog dosyalarını kullanarak veritabanı şemasında yapılacak değişiklikler sürüm kontrolüne alınabilir ve her ortamda (geliştirme, test, üretim) tutarlı bir şekilde uygulanabilir.


2. Liquibase'i Spring Boot ile Kullanma


Liquibase'i Spring Boot projesiyle entegre etmek için şu adımları izleyebilirsiniz.


Adım 1: Liquibase Bağımlılığını Ekleyin


Liquibase'i kullanmak için spring-boot-starter-data-jpa ve liquibase-core bağımlılıklarını pom.xml dosyanıza ekleyin.


pom.xml



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>


<dependency>

    <groupId>org.liquibase</groupId>

    <artifactId>liquibase-core</artifactId>

</dependency>



Adım 2: Liquibase Yapılandırması


Spring Boot projenizde application.properties veya application.yml dosyanızda Liquibase ile ilgili yapılandırmaları yapabilirsiniz.


application.properties



spring.datasource.url=jdbc:h2:mem:testdb

spring.datasource.driverClassName=org.h2.Driver

spring.datasource.username=sa

spring.datasource.password=


# Liquibase ayarları

spring.liquibase.enabled=true

spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml



Yukarıdaki ayarlar, H2 veritabanını kullanarak veritabanı bağlantısını sağlar ve Liquibase'in db/changelog/db.changelog-master.xml dosyasını kullanarak değişiklikleri yöneteceğini belirtir.


3. Changelog Dosyaları Oluşturma


Liquibase, changelog dosyalarını kullanarak veritabanı değişikliklerini izler ve uygular. Bu dosyalar XML, YAML, JSON veya SQL formatında olabilir. En yaygın kullanılan format XML'dir.


Adım 1: Changelog Dosyası Yapısı


Liquibase ile çalışırken genellikle bir ana changelog dosyası (db.changelog-master.xml) ve onun referans verdiği alt changelog dosyaları kullanılır.


db/changelog/db.changelog-master.xml



<?xml version="1.0" encoding="UTF-8"?>


<databaseChangeLog

    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog

    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">


    <include file="db/changelog/changesets/01-initial-schema.xml"/>

    <include file="db/changelog/changesets/02-add-products-table.xml"/>


</databaseChangeLog>



Bu dosya, Liquibase'in 01-initial-schema.xml ve 02-add-products-table.xml dosyalarını işleyeceğini belirtir.


Adım 2: Changeset Dosyaları Oluşturma


Her veritabanı değişikliği bir changeset içinde tanımlanır. Changeset'ler veritabanı üzerinde yapılacak her işlemi temsil eder ve genellikle tablo ekleme, silme veya sütun ekleme işlemlerini içerir.


01-initial-schema.xml



<databaseChangeLog

    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog

    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">


    <changeSet id="1" author="eda">

        <createTable tableName="users">

            <column name="id" type="BIGINT" autoIncrement="true">

                <constraints primaryKey="true"/>

            </column>

            <column name="name" type="VARCHAR(255)">

                <constraints nullable="false"/>

            </column>

            <column name="email" type="VARCHAR(255)">

                <constraints nullable="false" unique="true"/>

            </column>

        </createTable>

    </changeSet>


</databaseChangeLog>



Bu changeset, users adlı bir tablo oluşturur ve bu tabloya id, name, ve email sütunlarını ekler.


02-add-products-table.xml



<databaseChangeLog

    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog

    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">


    <changeSet id="2" author="eda">

        <createTable tableName="products">

            <column name="id" type="BIGINT" autoIncrement="true">

                <constraints primaryKey="true"/>

            </column>

            <column name="name" type="VARCHAR(255)">

                <constraints nullable="false"/>

            </column>

            <column name="price" type="DECIMAL(10, 2)">

                <constraints nullable="false"/>

            </column>

        </createTable>

    </changeSet>


</databaseChangeLog>



Bu changeset, products adında bir tablo oluşturur ve id, name, price sütunlarını içerir.


4. Liquibase ile Veritabanı Değişikliklerini Yürütme


Spring Boot uygulamanız başlatıldığında, Liquibase otomatik olarak yukarıda tanımlanan changelog dosyalarını bulur ve çalıştırır. Bu sayede veritabanınızda gerekli tablolar oluşturulur ve güncellemeler yapılır.


Liquibase, her changeSet'in daha önce çalıştırılıp çalıştırılmadığını izlemek için DATABASECHANGELOG adında bir tablo oluşturur. Bu tablo, her bir changeset'in hangi sırayla çalıştırıldığını ve kim tarafından oluşturulduğunu kaydeder.


5. Liquibase Komutları


Liquibase, veritabanı değişikliklerini uygulamak, kontrol etmek ve geri almak için çeşitli komutlar sunar. İşte bazı yaygın kullanılan komutlar:


  • update: Changelog dosyasındaki tüm değişiklikleri veritabanına uygular.
  • status: Veritabanında henüz uygulanmamış changeset'leri gösterir.
  • rollback: Belirli bir changeset'e kadar olan değişiklikleri geri alır.


Bu komutları çalıştırmak için Liquibase CLI kullanabilirsiniz ya da Spring Boot projeleri için Spring Boot'un sunduğu otomatik işlemleri kullanabilirsiniz.


6. Liquibase ile Rollback (Geri Alma)


Liquibase, veritabanında yapılan değişiklikleri geri almak için rollback işlemi sağlar. Bu işlem için changelog dosyalarınızda her changeSet'e bir rollback tanımlayabilirsiniz.


Örnek: Rollback Tanımlama



<changeSet id="2" author="eda">

    <createTable tableName="products">

        <column name="id" type="BIGINT" autoIncrement="true">

            <constraints primaryKey="true"/>

        </column>

        <column name="name" type="VARCHAR(255)">

            <constraints nullable="false"/>

        </column>

        <column name="price" type="DECIMAL(10, 2)">

            <constraints nullable="false"/>

        </column>

    </createTable>


    <rollback>

        <dropTable tableName="products"/>

    </rollback>

</changeSet>



Yukarıdaki rollback işlemi, products tablosu oluşturulduktan sonra bu tabloyu geri almak istediğinizde çalıştırılacak işlemi tanımlar.


7. Liquibase ile Versiyon Kontrolü ve CI/CD


Liquibase, veritabanı değişikliklerini izlemek ve sürüm kontrolüne almak için idealdir. Tüm değişiklikler kod deposunda saklanır ve bu sayede veritabanı değişiklikleri, CI/CD pipeline'

50. Spring Retry ile İstekleri Tekrarlama

  • Hatalı isteklerde otomatik tekrar denemeleri yapmak için Spring Retry kullanın:

  •   @Retryable(value = {RemoteAccessException.class}, maxAttempts = 3)
  •   public String callRemoteService() {
  •       return restTemplate.getForObject("http://remote-service/api", String.class);
  •   }

Spring Retry, bir işlemin başarısız olma durumunda belirli koşullara göre otomatik olarak tekrar denenmesini sağlayan bir kütüphanedir. Bu özellik, özellikle uzaktaki hizmetlere yapılan isteklerde hata durumlarında denemelerin otomatik olarak yapılması için kullanılır. Örneğin, bir API çağrısında geçici bir hata olduğunda Spring Retry, belirli sayıda tekrar deneme yaparak isteğin başarılı olma olasılığını artırabilir.


Spring Retry Nasıl Kullanılır?


Spring Retry, belirli hatalar veya istisnalar meydana geldiğinde işlemleri yeniden denemeyi sağlar. Kullanıcı maksimum deneme sayısını ve hangi istisnalarda tekrar deneme yapılacağını belirleyebilir.


1. Spring Retry Bağımlılığını Ekleyin


İlk adım, Spring Boot projenize spring-retry bağımlılığını eklemektir.


Maven:


<dependency>

    <groupId>org.springframework.retry</groupId>

    <artifactId>spring-retry</artifactId>

</dependency>

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-aop</artifactId>

</dependency>



Gradle:


implementation 'org.springframework.retry:spring-retry'

implementation 'org.springframework.boot:spring-boot-starter-aop'



2. Spring Retry Yapılandırması

Spring Retry’yi etkinleştirmek için Spring Boot uygulamanızda @EnableRetry anotasyonunu kullanmalısınız.



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.retry.annotation.EnableRetry;


@SpringBootApplication

@EnableRetry

public class RetryApplication {

    public static void main(String[] args) {

        SpringApplication.run(RetryApplication.class, args);

    }

}



3. @Retryable Anotasyonu ile Tekrar Deneme

@Retryable anotasyonu, bir method başarısız olduğunda bu methodun tekrar denenmesini sağlar. İlgili istisna fırlatıldığında işlemin yeniden denenmesini sağlamak için bu anotasyonu kullanabilirsiniz.


Örnek bir uzaktan hizmet çağrısı senaryosu:



import org.springframework.retry.annotation.Retryable;

import org.springframework.stereotype.Service;

import org.springframework.web.client.RestTemplate;

import org.springframework.web.client.ResourceAccessException;


@Service

public class RemoteService {


    private final RestTemplate restTemplate = new RestTemplate();


    @Retryable(value = {ResourceAccessException.class}, maxAttempts = 3)

    public String callRemoteService() {

        return restTemplate.getForObject("http://remote-service/api", String.class);

    }

}



Yukarıdaki örnekte:

  • @Retryable: ResourceAccessException fırlatıldığında methodun tekrar denenmesini sağlar.
  • maxAttempts = 3: İstek başarısız olduğunda en fazla 3 deneme yapılır.


4. @Recover Anotasyonu ile Hata Yönetimi

Eğer bir işlem belirtilen tekrar denemelerine rağmen başarısız olursa, bu durumda bir recovery (kurtarma) methodu çağrılabilir. Bu, işlemin başarılı olamaması durumunda yapılacak eylemi belirlemek için kullanılır.



import org.springframework.retry.annotation.Recover;

import org.springframework.stereotype.Service;


@Service

public class RemoteService {


    @Retryable(value = {ResourceAccessException.class}, maxAttempts = 3)

    public String callRemoteService() {

        // Uzak bir servise istek gönder

        return restTemplate.getForObject("http://remote-service/api", String.class);

    }


    @Recover

    public String recover(ResourceAccessException e) {

        // Hata durumunda yapılacak işlem

        System.out.println("İstek başarısız oldu: " + e.getMessage());

        return "Default response"; // Varsayılan bir yanıt döndür

    }

}



Bu örnekte, eğer maxAttempts = 3 denemesi başarısız olursa, recover methodu çağrılır ve burada hata durumunda yapılacak işlem belirlenir.


5. Geri Alma (Backoff) Stratejisi

Spring Retry, tekrar denemeleri arasında belirli bir gecikme süresi koymanızı da sağlar. Bu işleme backoff denir. @Retryable anotasyonu içinde backoff parametresi kullanılarak ayarlanabilir.



import org.springframework.retry.annotation.Backoff;

import org.springframework.retry.annotation.Retryable;

import org.springframework.stereotype.Service;


@Service

public class RemoteService {


    @Retryable(value = {ResourceAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000))

    public String callRemoteService() {

        return restTemplate.getForObject("http://remote-service/api", String.class);

    }

}



Yukarıdaki örnekte:

  • delay = 2000: Her deneme arasında 2 saniye bekleme süresi uygulanır. Yani, başarısızlık durumunda 2 saniye beklenip işlem tekrar denenir.


6. Spring Retry Özellikleri

  • maxAttempts: Belirtilen methodun maksimum kaç kez denenebileceğini ayarlar.
  • value: Hangi istisnaların fırlatıldığında methodun yeniden denenmesi gerektiğini belirtir.
  • backoff: Tekrar denemeler arasında bekleme süresini ayarlar.
  • @Recover: Eğer belirtilen denemelerden sonra method başarısız olursa, bu method devreye girer ve hata durumunda kurtarma işlemi yapılabilir.


Özet

Spring Retry, uygulamanızın hatalı işlemleri belirli sayıda otomatik olarak tekrar denemesini sağlayarak, geçici hatalardan dolayı başarısız olan işlemlerin kurtarılmasına yardımcı olur. Özellikle uzaktan hizmet çağrılarında veya ağ hatalarının geçici olabileceği durumlarda oldukça faydalıdır. @Retryable ve @Recover anotasyonları sayesinde uygulamanızda retry ve kurtarma mekanizmalarını kolayca entegre edebilirsiniz.

51. Spring Cloud Sleuth ile Dağıtık İzleme

  • Mikroservisler arasında istekleri izlemek ve Zipkin entegrasyonu ile izleri toplamak için Spring Cloud Sleuth kullanın.

51. Spring Cloud Sleuth ile Dağıtık İzleme

Spring Cloud Sleuth, mikroservisler arasında yapılan istekleri izlemek ve her isteğe bir benzersiz iz (trace) ve span ID atamak için kullanılan bir araçtır. Bu sayede, bir istek birden fazla mikroservisten geçse bile, tüm istek zincirini izleyebilir ve performans sorunlarını tespit edebilirsiniz. Ayrıca, Spring Cloud Sleuth, izleme verilerini toplamak ve görselleştirmek için Zipkin gibi dağıtık izleme sistemleriyle entegrasyon sağlar.


Adım Adım Spring Cloud Sleuth Kullanımı ve Zipkin Entegrasyonu


  1. Spring Cloud Sleuth ve Zipkin Bağımlılıklarını Ekleyin:
  2. Spring Cloud Sleuth’u projenize eklemek için pom.xml dosyasına gerekli bağımlılıkları ekleyin:


  3.    <dependency>
  4.        <groupId>org.springframework.cloud</groupId>
  5.        <artifactId>spring-cloud-starter-sleuth</artifactId>
  6.    </dependency>
  7.    <dependency>
  8.        <groupId>org.springframework.cloud</groupId>
  9.        <artifactId>spring-cloud-sleuth-zipkin</artifactId>
  10.    </dependency>


  11. Bu bağımlılıklar, mikroservisler arası istekleri izlemek için Sleuth ve topladığı iz bilgilerini Zipkin’e göndermek için gerekli entegrasyonu sağlar.

  12. Zipkin Server’ı Başlatın:
  13. İzleme verilerini toplamak ve analiz etmek için bir Zipkin sunucusu çalıştırmanız gerekir. Zipkin'i Docker kullanarak kolayca başlatabilirsiniz. Terminalde şu komutu çalıştırarak Zipkin sunucusunu ayağa kaldırabilirsiniz:


  14.    docker run -d -p 9411:9411 openzipkin/zipkin


  15. Bu komut, Zipkin sunucusunu localhost:9411 adresinde çalıştırır.

  16. Uygulama Ayarlarını Yapılandırın:
  17. Uygulamanızın izleme bilgilerini Zipkin’e gönderebilmesi için application.properties veya application.yml dosyanızda bazı ayarlamalar yapmanız gerekir.

  18. application.yml dosyasına şu ayarları ekleyebilirsiniz:


  19.    spring:
  20.      zipkin:
  21.        base-url: http://localhost:9411  # Zipkin sunucusunun URL'si
  22.        enabled: true
  23.      sleuth:
  24.        sampler:
  25.          probability: 1.0  # Tüm isteklerin izlenmesi için olasılığı %100 yapıyoruz


  26. Bu ayarlar, uygulamanın Zipkin’e verileri göndermesini sağlar ve tüm isteklerin izlenmesi gerektiğini belirtir. Eğer sadece belli bir yüzdelik dilimde istekleri izlemek isterseniz, probability değerini düşürebilirsiniz (örneğin 0.1).

  27. Mikroservisler Arası İstekleri İzleme:
  28. Spring Cloud Sleuth, bir mikroservisten diğerine yapılan istekler sırasında izleme verilerini otomatik olarak iletir. Örneğin, bir mikroservisten diğerine bir REST API isteği yapıldığında, her iki servis de aynı izleme ID'sini (trace ID) paylaşır. Böylece, bu isteklerin hangi servisler arasında geçtiğini kolayca görebilirsiniz.

  29. Örnek bir mikroservis çağrısı:


  30.    @RestController
  31.    public class MyController {
  32.        @Autowired
  33.        private RestTemplate restTemplate;
  34.    
  35.        @GetMapping("/call")
  36.        public String callOtherService() {
  37.            return restTemplate.getForObject("http://other-service/endpoint", String.class);
  38.        }
  39.    }


  40. Bu istek sırasında Spring Cloud Sleuth, trace ID ve span ID oluşturur ve other-service servisine yapılan isteği izler. Bu sayede, Zipkin üzerinden tüm zinciri görebilirsiniz.

  41. Zipkin Üzerinden İzleme Verilerini Görüntüleyin:
  42. Uygulamanız çalıştıktan sonra, http://localhost:9411 adresindeki Zipkin UI’ye giderek izlenen istekleri görüntüleyebilirsiniz. Zipkin, her isteğin hangi servisten hangi servise geçtiğini, ne kadar süre aldığını ve performans detaylarını gösterir.


Zipkin Kullanımı ve Görselleştirme


  • Trace ID ve Span ID: Trace ID, bir istek zincirini izlemek için kullanılır. Span ID ise her mikroservisteki belirli bir işlemi temsil eder.
  • UI: Zipkin UI üzerinden trace ID'leri ile sorgulama yaparak, hangi isteklerin ne kadar süre aldığını ve mikroservisler arasındaki performans sorunlarını kolayca tespit edebilirsiniz.


Özet


  • Spring Cloud Sleuth, mikroservisler arasında yapılan istekleri izler ve performans analizlerini kolaylaştırır.
  • Zipkin ile entegrasyon sayesinde, izleme verilerini toplayabilir ve görselleştirebilirsiniz.
  • Bu entegrasyon, mikroservis tabanlı sistemlerde performans iyileştirmeleri yapmak ve hataları tespit etmek için oldukça faydalıdır.


Bu yapıyı kurarak dağıtık sistemlerinizdeki izleme kapasitenizi artırabilir ve sisteminizin hangi noktalarında darboğaz yaşandığını görebilirsiniz.

52. Güvenli Konfigürasyonlar için Vault

  • HashiCorp Vault kullanarak güvenli konfigürasyon yönetimi sağlayın ve gizli anahtarları yönetmek için entegrasyon yapın.

52. Güvenli Konfigürasyonlar için Vault Kullanımı


HashiCorp Vault, uygulamalarda kullanılan gizli anahtarları, kimlik bilgilerini ve hassas verileri güvenli bir şekilde depolamak ve yönetmek için kullanılan güçlü bir araçtır. Vault kullanarak uygulama konfigürasyonlarındaki gizli verilerin sızdırılmasını önleyebilir, dinamik kimlik bilgileri sağlayabilir ve şifreleme gibi güvenlik hizmetlerini entegre edebilirsiniz. Spring Boot projelerinde Vault ile güvenli konfigürasyon yönetimi ve gizli anahtarların saklanması sağlanabilir.


Aşağıda, Spring Boot projelerinde HashiCorp Vault entegrasyonu yaparak güvenli konfigürasyon yönetimini adım adım anlatıyorum.


1. Vault Nedir?


Vault, hassas bilgilerin güvenli bir şekilde saklanmasını ve yönetilmesini sağlar. Bunlar arasında API anahtarları, veritabanı kimlik bilgileri, erişim anahtarları gibi gizli bilgiler bulunur. Vault, şifreleme işlemlerini yönetir ve güvenli erişim sağlar.


2. HashiCorp Vault'un Avantajları


  • Gizli Anahtar Yönetimi: Vault, veritabanı şifreleri, API anahtarları gibi gizli bilgileri güvenli bir şekilde saklar ve yönetir.
  • Dinamik Kimlik Bilgileri: Vault, belirli bir süre için geçerli olacak dinamik kimlik bilgileri sağlayabilir.
  • Şifreleme: Verilerinizi Vault ile şifreleyip çözebilirsiniz.
  • Erişim Kontrolü: Hassas verilere erişim yetkilerini yönetebilirsiniz.


3. Vault'u Spring Boot ile Kullanma


Spring Boot projelerinde Spring Cloud Vault ile Vault’u entegre edebilir, uygulama konfigürasyonlarını güvenli bir şekilde yönetebilirsiniz.


Adım 1: Vault Sunucusunu Kurun


Öncelikle HashiCorp Vault sunucusunu kurmalısınız. Bunun için Vault’u yerel olarak çalıştırabilir veya bir bulut sağlayıcısında hizmet olarak kullanabilirsiniz.


Vault'u yerel ortamda başlatmak için:



vault server -dev



Bu komut, yerel bir Vault sunucusu başlatır. Sunucu başlatıldığında Vault'un dev modda olduğu bir token üretilecektir. root token ile erişim sağlayabilirsiniz.


Adım 2: Vault Bağımlılıklarını Ekleyin


Spring Boot projesinde Vault ile güvenli konfigürasyon yönetimi yapmak için Spring Cloud Vault bağımlılıklarını ekleyin.


pom.xml



<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-vault-config</artifactId>

</dependency>



Adım 3: Vault Yapılandırması


Vault ile Spring Boot uygulamasını entegre etmek için uygulamanın konfigürasyon dosyasında Vault bağlantı ayarlarını yapmanız gerekir.


application.properties



spring.cloud.vault.uri=http://localhost:8200

spring.cloud.vault.token=<VAULT_TOKEN>  # Vault root token veya erişim token

spring.cloud.vault.kv.enabled=true

spring.cloud.vault.kv.backend=secret

spring.cloud.vault.kv.default-context=application

spring.cloud.vault.kv.profile-separator=/



Açıklamalar:

  • spring.cloud.vault.uri: Vault sunucusunun URL’sini belirtir. Varsayılan olarak yerel ortamda http://localhost:8200 kullanılır.
  • spring.cloud.vault.token: Vault’a erişim için kullanılacak token. Bu token, Vault üzerinde yönetilen hassas verilere erişimi sağlar.
  • spring.cloud.vault.kv.backend: Vault'ta kullanılan anahtar-değer backend'ini belirtir. Varsayılan olarak secret kullanılır.
  • spring.cloud.vault.kv.default-context: Uygulamanın Vault'ta hangi konteks üzerinde çalışacağını belirtir. Örneğin, application adı altında güvenli bilgileri saklayabilirsiniz.


Adım 4: Vault Üzerinde Gizli Anahtarlar Oluşturma


Vault üzerinde uygulama konfigürasyonlarını ve gizli anahtarları saklamak için bir secret oluşturun. Örneğin, API anahtarı veya veritabanı şifresini saklayalım.


Vault CLI kullanarak aşağıdaki komutla bir gizli anahtar ekleyebilirsiniz:



vault kv put secret/application api-key=my-secret-api-key db-password=my-db-password



Bu komut, secret/application yolunda api-key ve db-password gibi gizli bilgileri saklar.


Adım 5: Spring Boot Uygulamasında Gizli Bilgilere Erişim


Artık Vault’a eklediğiniz gizli bilgilere Spring Boot uygulamanızda erişebilirsiniz. application.properties içinde tanımlanan bilgiler, Vault'tan otomatik olarak çekilecek ve uygulama başlatıldığında kullanılacaktır.


application.properties:



example.api.key=${api-key}

example.db.password=${db-password}



Bu yapılandırma sayesinde api-key ve db-password değerleri, Vault’tan alınarak uygulamanıza enjekte edilir.


Adım 6: Spring Boot Uygulamasında Gizli Anahtarları Kullanma


Gizli anahtarları kullanarak uygulamanızın servislerine veya repository sınıflarına bu bilgileri enjekte edebilirsiniz.


ConfigService.java



import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Service;


@Service

public class ConfigService {


    @Value("${example.api.key}")

    private String apiKey;


    @Value("${example.db.password}")

    private String dbPassword;


    public void printConfig() {

        System.out.println("API Key: " + apiKey);

        System.out.println("DB Password: " + dbPassword);

    }

}



Bu servis sınıfı, Vault üzerinde saklanan api-key ve db-password değerlerini kullanarak uygulama içinde işlem yapar.


4. Vault ile Dinamik Kimlik Bilgileri Sağlama


Vault’un en güçlü özelliklerinden biri, dinamik kimlik bilgileri sağlamasıdır. Örneğin, veritabanına bağlanmak için kullanılan kullanıcı adı ve şifre gibi bilgileri Vault'tan alarak dinamik bir şekilde kullanabilirsiniz. Vault, belirli bir süre için geçerli olacak dinamik kimlik bilgileri sağlayabilir ve süresi dolduğunda bunları iptal edebilir.


Vault üzerinde PostgreSQL için dinamik kimlik bilgileri ayarlama:


Vault’ta bir PostgreSQL veritabanı backend’i yapılandırarak her bağlantı için dinamik olarak kullanıcı adı ve şifre üretebilirsiniz. Bu özellik, yüksek güvenlik gerektiren ortamlarda kullanışlıdır.



vault secrets enable database

vault write database/config/my-postgresql \

    plugin_name=postgresql-database-plugin \

    allowed_roles="my-role" \

    connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb?sslmode=disable" \

    username="dbadmin" \

    password="mypassword"


vault write database/roles/my-role \

    db_name=my-postgresql \

    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" \

    default_ttl="1h" \

    max_ttl="24h"



Bu komutlar, PostgreSQL için dinamik kullanıcı adı ve şifre sağlayan bir Vault backend’i oluşturur. Spring Boot uygulamanız bu bilgileri Vault’tan dinamik olarak alabilir ve kullanabilir.


5. Vault ile Şifreleme Hizmetleri


Vault ayrıca veri şifreleme ve çözme işlemlerini gerçekleştirebilir. Bu sayede uygulamanızda hassas verileri şifreleyebilir ve sadece gerektiğinde çözebilirsiniz.


Vault’un Transit Secret Engine özelliği ile verileri şifrelemek ve çözmek mümkündür:



vault write transit/encrypt/my-key plaintext=$(echo "my-secret-data" | base64)

vault write transit/decrypt/my-key ciphertext=<ciphertext-from-encrypt>



Bu komutlar, verilerinizi Vault kullanarak güvenli bir şekilde şifreler ve gerektiğinde çözer.


6. Spring Vault ile Vault Policy Ayarları


Vault kullanırken hassas verilere sadece gerekli yetkilere sahip kullanıcıların erişmesini sağlamak için Vault politikaları kullanabilirsiniz. Her uygulama veya kullanıcıya özel erişim yetkileri tanımlayarak güvenliği artırabilirsiniz.



vault policy write my-policy - <<EOF

path "secret/*" {

  capabilities = ["create", "read", "update", "delete", "list"]

}

EOF




53. ElasticSearch ile Loglama

  • Spring Boot uygulamanızda logları ElasticSearch üzerine yazdırarak merkezi bir log yönetim sistemi kurun.

ElasticSearch, büyük veri kümeleri üzerinde hızlı arama ve analiz yapmak için kullanılan güçlü bir arama motorudur. Spring Boot uygulamanızda logları ElasticSearch üzerine yazdırarak merkezi bir log yönetim sistemi kurabilir ve uygulama loglarınızı daha rahat bir şekilde yönetip analiz edebilirsiniz. Bu genellikle ELK Stack (ElasticSearch, Logstash, Kibana) adı verilen bir sistemin parçası olarak kullanılır, ancak doğrudan Spring Boot uygulaması ile ElasticSearch'e log yazdırmak da mümkündür.


1. ElasticSearch Bağlantısı ve Yapılandırması


Adım 1: ElasticSearch Kurulumu

İlk olarak, ElasticSearch'ü sisteminize kurmanız gerekmektedir. ElasticSearch, doğrudan sistemde çalıştırılabilir ya da bir Docker konteyneri olarak başlatılabilir.


ElasticSearch'i Docker ile başlatma:


docker run -d -p 9200:9200 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.10.1



ElasticSearch bu komutla localhost:9200 adresinde çalışmaya başlayacaktır.


Adım 2: Spring Boot Uygulamanızda ElasticSearch Bağımlılığını Ekleyin

Spring Boot uygulamanızda logları ElasticSearch'e yazdırabilmek için ElasticSearch ve loglama kütüphanesine ihtiyaç duyacaksınız. Logback veya Log4j2 gibi loglama araçlarını kullanabilirsiniz.


Maven:


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>

</dependency>


<dependency>

    <groupId>net.logstash.logback</groupId>

    <artifactId>logstash-logback-encoder</artifactId>

    <version>6.6</version>

</dependency>



Gradle:


implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'

implementation 'net.logstash.logback:logstash-logback-encoder:6.6'



Adım 3: Logback Yapılandırması (logback-spring.xml)


Spring Boot ile logları ElasticSearch'e yazdırmak için Logback yapılandırmasını güncellemeniz gerekmektedir. logback-spring.xml dosyasını uygulamanızın src/main/resources dizinine ekleyin ve aşağıdaki gibi yapılandırın:



<configuration>

    <appender name="ELASTIC" class="net.logstash.logback.appender.LogstashTcpSocketAppender">

        <destination>localhost:9200</destination>

        <encoder class="net.logstash.logback.encoder.LogstashEncoder" />

    </appender>


    <root level="INFO">

        <appender-ref ref="ELASTIC" />

    </root>

</configuration>



Bu yapılandırma, logları ElasticSearch'ün dinlediği porta (bu örnekte localhost:9200) gönderecek şekilde ayarlanmıştır. Logstash entegrasyonu ile daha gelişmiş yapılandırmalar yapılabilir, ancak bu örnekte doğrudan ElasticSearch'e yazdırmayı ele alıyoruz.


2. Logstash Entegrasyonu (İsteğe Bağlı)


ElasticSearch'e log yazdırmanın en iyi yollarından biri Logstash kullanmaktır. Logstash, farklı kaynaklardan gelen logları toplar, filtreler ve ElasticSearch gibi bir hedefe gönderir.


Adım 1: Logstash Kurulumu


Logstash'i Docker ile başlatma:


docker run -d -p 5044:5044 -p 9600:9600 docker.elastic.co/logstash/logstash:7.10.1



Adım 2: Logstash Yapılandırması


Logstash yapılandırması için bir logstash.conf dosyası oluşturun ve aşağıdaki gibi yapılandırın:



input {

  tcp {

    port => 5044

  }

}


filter {

  json {

    source => "message"

  }

}


output {

  elasticsearch {

    hosts => ["http://localhost:9200"]

    index => "spring-boot-logs"

  }

}



Bu yapılandırma, Logstash'in TCP üzerinden gelen logları dinlemesini ve bunları ElasticSearch'e göndermesini sağlar.


3. Spring Boot Uygulamanızdan Log Yazdırma


Artık Spring Boot uygulamanızda ElasticSearch'e log yazdıracak şekilde yapılandırma yapıldığında, standart log yazma işlemleri ile loglar ElasticSearch'e iletilecektir. Örneğin, herhangi bir kontrolcü veya servis sınıfında log yazdırmak:



import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class LogController {


    private static final Logger logger = LoggerFactory.getLogger(LogController.class);


    @GetMapping("/log")

    public String logMessage() {

        logger.info("This is a test log message.");

        return "Log message sent!";

    }

}



Bu endpoint'e bir istek gönderildiğinde log mesajı ElasticSearch'e iletilecektir.


4. Kibana ile Logları Görselleştirme


ElasticSearch'e gönderilen logları daha kolay incelemek ve analiz etmek için Kibana kullanılabilir. Kibana, ElasticSearch ile entegre olan güçlü bir görselleştirme aracıdır.


Adım 1: Kibana Kurulumu


Kibana'yı Docker ile başlatma:


docker run -d -p 5601:5601 docker.elastic.co/kibana/kibana:7.10.1



Kibana, localhost:5601 adresinde çalışacaktır.


Adım 2: Kibana'da Logları Görüntüleme


Kibana arayüzünden ElasticSearch'ü kaynak olarak ekleyebilir ve "spring-boot-logs" gibi bir index pattern tanımlayarak logları görüntüleyebilirsiniz.


5. Sonuç


Bu adımlarla, Spring Boot uygulamanızın loglarını ElasticSearch üzerine yazdırarak merkezi bir log yönetim sistemi kurabilirsiniz. Bu yapı, logların toplanmasını, analiz edilmesini ve görselleştirilmesini kolaylaştırır. Özellikle dağıtık sistemlerde logların merkezi bir yerde toplanması ve analiz edilmesi, sorunların tespit edilmesi ve izlenmesi açısından büyük fayda sağlar.

54. Kafka ile Mesaj Kuyruğu Entegrasyonu

  • Spring Boot ile Apache Kafka kullanarak mikroservisler arasında mesajlaşma altyapısı kurun:

  •   <dependency>
  •       <groupId>org.springframework.kafka</groupId>
  •       <artifactId>spring-kafka</artifactId>
  •   </dependency>

54. Kafka ile Mesaj Kuyruğu Entegrasyonu

Apache Kafka, yüksek hacimli veri akışını yönetmek ve mikroservisler arasında mesajlaşmayı sağlamak için kullanılan popüler bir dağıtık mesaj kuyruğu sistemidir. Kafka, özellikle mikroservis mimarilerinde, servislerin birbirleriyle senkron veya asenkron olarak haberleşmesini sağlar. Spring Boot ile Kafka entegrasyonu, veri akışını yönetmek ve mikroservisler arasında güvenli bir mesajlaşma altyapısı kurmak için oldukça etkili bir yöntemdir.


Adım Adım Spring Boot ile Kafka Entegrasyonu


  1. Kafka Bağımlılığını Ekleyin:
  2. Spring Boot projenize Kafka desteği eklemek için pom.xml dosyasına aşağıdaki bağımlılığı ekleyin:


  3.    <dependency>
  4.        <groupId>org.springframework.kafka</groupId>
  5.        <artifactId>spring-kafka</artifactId>
  6.    </dependency>


  7. Kafka Broker'ı Kurun:
  8. Kafka Broker'ı yerel olarak çalıştırmak için Apache Kafka'nın kurulumu gereklidir. Kafka’yı Docker ile hızlıca başlatabilirsiniz. Zookeeper ve Kafka Broker'ı Docker ile çalıştırmak için şu komutları kullanın:


  9.    docker run -d --name zookeeper -p 2181:2181 zookeeper:3.6.3
  10.    docker run -d --name kafka -p 9092:9092 -e KAFKA_ZOOKEEPER_CONNECT=localhost:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 confluentinc/cp-kafka


  11. Bu komutlar, Zookeeper’ı 2181, Kafka’yı ise 9092 portunda çalıştıracaktır.

  12. Kafka Yapılandırmasını Ekleyin:
  13. application.yml veya application.properties dosyanıza Kafka yapılandırmalarını ekleyin. Aşağıda örnek bir application.yml dosyası yer almakta:


  14.    spring:
  15.      kafka:
  16.        bootstrap-servers: localhost:9092
  17.        consumer:
  18.          group-id: my-group
  19.          auto-offset-reset: earliest
  20.          key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
  21.          value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
  22.        producer:
  23.          key-serializer: org.apache.kafka.common.serialization.StringSerializer
  24.          value-serializer: org.apache.kafka.common.serialization.StringSerializer


    • bootstrap-servers: Kafka broker’larının adresi.
    • consumer: Tüketici yapılandırmaları. Mesajları almak için kullanılan ayarlar.
    • producer: Üretici yapılandırmaları. Mesajları kuyruğa göndermek için kullanılır.


  1. Üretici (Producer) Servisini Yazın:
  2. Kafka'ya mesaj gönderen bir üretici servisi oluşturun. Aşağıda örnek bir Kafka üretici sınıfı gösterilmiştir:


  3.    import org.springframework.kafka.core.KafkaTemplate;
  4.    import org.springframework.stereotype.Service;
  5.    
  6.    @Service
  7.    public class KafkaProducer {
  8.    
  9.        private final KafkaTemplate<String, String> kafkaTemplate;
  10.    
  11.        public KafkaProducer(KafkaTemplate<String, String> kafkaTemplate) {
  12.            this.kafkaTemplate = kafkaTemplate;
  13.        }
  14.    
  15.        public void sendMessage(String topic, String message) {
  16.            kafkaTemplate.send(topic, message);
  17.            System.out.println("Mesaj gönderildi: " + message);
  18.        }
  19.    }


  20. Bu sınıf, belirtilen topic’e mesaj gönderir.

  21. Tüketici (Consumer) Servisini Yazın:
  22. Kafka’dan mesajları alacak bir tüketici servisi yazın. Aşağıda örnek bir Kafka tüketici sınıfı yer almaktadır:


  23.    import org.apache.kafka.clients.consumer.ConsumerRecord;
  24.    import org.springframework.kafka.annotation.KafkaListener;
  25.    import org.springframework.stereotype.Service;
  26.    
  27.    @Service
  28.    public class KafkaConsumer {
  29.    
  30.        @KafkaListener(topics = "my-topic", groupId = "my-group")
  31.        public void listen(ConsumerRecord<String, String> record) {
  32.            System.out.println("Mesaj alındı: " + record.value());
  33.        }
  34.    }


  35. Bu sınıf, belirtilen my-topic başlığına gönderilen mesajları dinler ve çıktısını verir.

  36. Kafka Producer ve Consumer Testi:
  37. RestController üzerinden Kafka'ya mesaj göndermek ve mesajları almak için bir kontrolcü oluşturun.


  38.    import org.springframework.web.bind.annotation.GetMapping;
  39.    import org.springframework.web.bind.annotation.RequestParam;
  40.    import org.springframework.web.bind.annotation.RestController;
  41.    
  42.    @RestController
  43.    public class KafkaController {
  44.    
  45.        private final KafkaProducer kafkaProducer;
  46.    
  47.        public KafkaController(KafkaProducer kafkaProducer) {
  48.            this.kafkaProducer = kafkaProducer;
  49.        }
  50.    
  51.        @GetMapping("/send")
  52.        public String sendMessage(@RequestParam("message") String message) {
  53.            kafkaProducer.sendMessage("my-topic", message);
  54.            return "Mesaj gönderildi: " + message;
  55.        }
  56.    }


    • /send?message=... endpoint’ine bir istek gönderdiğinizde, bu mesaj Kafka’ya gönderilecektir.


  1. Kafka Tüketici ve Üretici Entegrasyonunu Test Edin:
  2. Uygulamanız çalıştığında, /send endpoint’ine bir istek göndererek Kafka'ya mesaj gönderin. Kafka Tüketici sınıfı, bu mesajı otomatik olarak dinleyip ekranda gösterecektir.


Özet

  • Kafka, mikroservisler arasında mesajlaşma altyapısı kurmak için yüksek performanslı ve dağıtık bir sistemdir.
  • Spring Kafka ile kolayca Kafka üretici ve tüketici servisleri oluşturabilir, mikroservisleriniz arasında mesajlaşmayı yönetebilirsiniz.
  • Kafka’nın sağladığı ölçeklenebilirlik ve esneklik ile sisteminizde büyük veri akışlarını yönetebilir ve asenkron mesajlaşmayı kolayca hayata geçirebilirsiniz.


Bu yapı, mikroservisler arasında güvenilir ve hızlı veri alışverişi sağlamak için oldukça güçlü bir çözümdür.

55. RabbitMQ ile Mesajlaşma

  • RabbitMQ entegrasyonu ile uygulamalar arasında mesaj gönderip alın. spring-boot-starter-amqp bağımlılığını kullanarak konfigürasyon yapın:

  •   <dependency>
  •       <groupId>org.springframework.boot</groupId>
  •       <artifactId>spring-boot-starter-amqp</artifactId>
  •   </dependency>

Spring Boot ile RabbitMQ kullanarak mesajlaşma işlemleri gerçekleştirmek oldukça yaygın bir yöntemdir. RabbitMQ, mesajların farklı uygulamalar veya bileşenler arasında taşınmasına olanak tanıyan bir mesaj kuyruklama sistemidir. Spring Boot ile RabbitMQ’yu entegre etmek için aşağıdaki adımları izleyebilirsiniz:


1. Proje Bağımlılıklarını Ayarlama

Spring Boot ile RabbitMQ'yu entegre etmek için önce gerekli bağımlılığı pom.xml dosyanıza ekleyin. RabbitMQ için spring-boot-starter-amqp bağımlılığı kullanılır.



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-amqp</artifactId>

</dependency>



Eğer Gradle kullanıyorsanız, aşağıdaki bağımlılığı build.gradle dosyanıza ekleyin:



implementation 'org.springframework.boot:spring-boot-starter-amqp'



2. RabbitMQ Konfigürasyonu

RabbitMQ ile bağlantı kurabilmek için application.properties veya application.yml dosyasına RabbitMQ sunucusunun yapılandırmasını ekleyin.


application.properties:



spring.rabbitmq.host=localhost

spring.rabbitmq.port=5672

spring.rabbitmq.username=guest

spring.rabbitmq.password=guest



application.yml:



spring:

  rabbitmq:

    host: localhost

    port: 5672

    username: guest

    password: guest



Eğer RabbitMQ sunucunuz farklı bir adreste çalışıyorsa, host ve port bilgilerini buna göre düzenleyin.


3. Mesaj Kuyruğunu ve Exchange Yapısını Tanımlama


RabbitMQ'da kuyrukları, exchange'leri ve binding'leri (bağlantıları) tanımlamanız gerekir. Aşağıda bir örnek Spring Bean tanımı bulunmaktadır:



import org.springframework.amqp.core.Queue;

import org.springframework.amqp.core.TopicExchange;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;


@Configuration

public class RabbitMQConfig {


    // Kuyruk tanımı

    @Bean

    public Queue queue() {

        return new Queue("myQueue", true);  // Kuyruğun kalıcı olup olmadığını belirtebilirsiniz

    }


    // Exchange tanımı

    @Bean

    public TopicExchange exchange() {

        return new TopicExchange("myExchange");

    }


    // Kuyruğu Exchange'e bağlama

    @Bean

    public Binding binding(Queue queue, TopicExchange exchange) {

        return BindingBuilder.bind(queue).to(exchange).with("routing.key");

    }

}



Bu örnekte:

  • myQueue adında bir kuyruk oluşturulmuştur.
  • myExchange adında bir topic exchange tanımlanmıştır.
  • Mesajlar belirli bir routing key ile exchange'den kuyruğa yönlendirilmiştir.


4. Mesaj Gönderici (Producer) Tanımlama


Mesajları RabbitMQ’ya gönderecek bir gönderici (producer) tanımlamanız gerekir. Aşağıda bir mesaj gönderici sınıfı örneği verilmiştir:



import org.springframework.amqp.rabbit.core.RabbitTemplate;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


@Service

public class MessageSender {


    @Autowired

    private RabbitTemplate rabbitTemplate;


    private static final String EXCHANGE_NAME = "myExchange";

    private static final String ROUTING_KEY = "routing.key";


    public void sendMessage(String message) {

        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING_KEY, message);

        System.out.println("Mesaj gönderildi: " + message);

    }

}



Bu sınıfta:

  • RabbitTemplate kullanılarak myExchange exchange'ine ve belirtilen routing.key ile mesaj gönderilmektedir.


5. Mesaj Alıcı (Consumer) Tanımlama


Mesajları dinlemek için bir alıcı (consumer) tanımlamanız gerekir. Bunun için Spring’in @RabbitListener anotasyonunu kullanabilirsiniz.



import org.springframework.amqp.rabbit.annotation.RabbitListener;

import org.springframework.stereotype.Service;


@Service

public class MessageListener {


    @RabbitListener(queues = "myQueue")

    public void receiveMessage(String message) {

        System.out.println("Mesaj alındı: " + message);

    }

}



Bu sınıfta:

  • @RabbitListener anotasyonu ile myQueue kuyruğundan gelen mesajlar dinlenir ve bu mesajlar işlendiğinde konsola yazdırılır.


6. Spring Boot Uygulamasını Başlatma


Tüm konfigürasyonlar tamamlandığında, uygulamanızı başlatabilirsiniz. Uygulama çalışırken mesaj gönderici sınıfını kullanarak RabbitMQ kuyruğuna mesaj gönderebilir ve dinleyici ile bu mesajları alabilirsiniz.


Örneğin, MessageSender sınıfını bir REST kontrolcüsü ile entegre edebilir ve bir HTTP isteği ile mesaj gönderilmesini sağlayabilirsiniz:



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class MessageController {


    @Autowired

    private MessageSender messageSender;


    @GetMapping("/send")

    public String sendMessage(@RequestParam("msg") String message) {

        messageSender.sendMessage(message);

        return "Mesaj gönderildi: " + message;

    }

}



Bu örnekte, /send endpoint'ine bir GET isteği yaparak mesaj gönderebilirsiniz:



http://localhost:8080/send?msg=Merhaba



Sonuç


Bu adımları takip ederek Spring Boot uygulamanızda RabbitMQ ile mesajlaşma işlemlerini kolayca gerçekleştirebilirsiniz. RabbitMQ, mikroservis mimarilerinde servisler arasında asenkron mesajlaşmayı sağlamak için güçlü bir araçtır.

56. Spring Cloud Stream

  • Spring Cloud Stream kullanarak uygulamalar arasında mesajlaşma yeteneği sağlayın ve çeşitli mesajlaşma sistemleriyle entegre olun (Kafka, RabbitMQ vb.).

56. Spring Cloud Stream Kullanımı


Spring Cloud Stream, uygulamalar arasında mesajlaşmayı sağlayan, Spring Boot ile entegre olan bir mikroservis mesajlaşma framework'üdür. Spring Cloud Stream, mesaj yönlendirme ve işleme süreçlerini basitleştirir ve arka planda Apache Kafka, RabbitMQ gibi mesajlaşma sistemleriyle entegre olarak çalışır. Bu sistemler arasında mesaj gönderme, alma ve işleme işlemlerini kolaylaştırır.


Spring Cloud Stream, mesaj üreticisi (producer) ve mesaj tüketicisi (consumer) mantığını kullanarak asenkron mesajlaşma sağlar. Aşağıda, Spring Cloud Stream ile nasıl mesajlaşma yapabileceğinizi ve Kafka ile nasıl entegre olabileceğinizi adım adım anlatıyorum.


1. Spring Cloud Stream Nedir?


Spring Cloud Stream, farklı mesajlaşma sistemleri üzerinde çalışan uygulamalar arasında mesaj alışverişini soyutlayan bir katman sağlar. Spring Boot ile entegre çalışan bu yapı, publish-subscribe, event-driven (olay tabanlı) ve point-to-point mesajlaşma modellerini destekler.


  • Producer: Mesaj üreten bileşen.
  • Consumer: Mesaj tüketen bileşen.


Spring Cloud Stream, mesajların hangi sistemlere gönderileceğini ya da nereden alınacağını belirten binding kavramını kullanır. Mesajlar, channels üzerinden taşınır ve bu kanallar belirli bir mesajlaşma sistemine bağlı olabilir (Kafka, RabbitMQ vb.).


2. Spring Cloud Stream Yapılandırması


Spring Cloud Stream kullanarak mesajlaşma işlemleri yapabilmek için projenizi uygun şekilde yapılandırmanız gerekir.


Adım 1: Bağımlılıkları Ekleyin


İlk olarak, Spring Cloud Stream ve kullanmak istediğiniz mesajlaşma sistemi (Kafka veya RabbitMQ gibi) için gerekli bağımlılıkları pom.xml dosyasına ekleyin. Aşağıda Kafka entegrasyonu için gerekli bağımlılıklar gösterilmiştir.


pom.xml (Kafka ile)



<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-stream-kafka</artifactId>

</dependency>



Eğer RabbitMQ ile entegre olmak istiyorsanız, aşağıdaki bağımlılığı ekleyebilirsiniz:



<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>

</dependency>



Adım 2: application.properties ile Yapılandırma


Spring Cloud Stream kullanarak bir mesajlaşma sistemi ile bağlanmak için gerekli bağlantı ayarlarını application.properties dosyanıza ekleyin. Örneğin, Kafka ile çalışıyorsanız Kafka broker bağlantı ayarlarını yapmanız gerekir.


application.properties (Kafka için)



spring.cloud.stream.bindings.output.destination=my-topic

spring.cloud.stream.bindings.input.destination=my-topic


spring.cloud.stream.kafka.binder.brokers=localhost:9092

spring.cloud.stream.kafka.binder.zkNodes=localhost:2181



  • spring.cloud.stream.bindings.output.destination: Üretilen mesajın gönderileceği Kafka topic adı.
  • spring.cloud.stream.bindings.input.destination: Tüketilecek mesajın alındığı Kafka topic adı.


3. Mesaj Üretici (Producer) Oluşturma


Bir mesaj üretici (producer) oluşturmak için, @EnableBinding anotasyonu kullanılarak bir çıktı kanalı tanımlanır ve bu kanaldan mesajlar gönderilir.


Producer Service


Aşağıda bir mesaj üreten (producer) servis örneği verilmiştir. Mesajlar belirli bir Kafka topic'ine gönderilir.



import org.springframework.cloud.stream.annotation.EnableBinding;

import org.springframework.cloud.stream.messaging.Source;

import org.springframework.messaging.support.MessageBuilder;

import org.springframework.stereotype.Service;


@Service

@EnableBinding(Source.class)  // Mesaj gönderen bileşen olarak yapılandırma

public class MessageProducer {


    private final Source source;


    public MessageProducer(Source source) {

        this.source = source;

    }


    public void sendMessage(String message) {

        source.output().send(MessageBuilder.withPayload(message).build());

        System.out.println("Mesaj gönderildi: " + message);

    }

}



Açıklamalar:

  • @EnableBinding(Source.class): Bu anotasyon, bir output kanalı oluşturur ve bu kanaldan mesajların gönderilmesini sağlar.
  • source.output().send(): Mesajın Kafka topic'ine gönderilmesini sağlar.
  • MessageBuilder: Gönderilen mesajın içeriğini tanımlamak için kullanılır.


4. Mesaj Tüketici (Consumer) Oluşturma


Mesaj tüketici (consumer) bir uygulama, belirli bir topic'e gönderilen mesajları dinler ve işler. Aşağıda bir mesaj tüketen (consumer) servis örneği verilmiştir.


Consumer Service



import org.springframework.cloud.stream.annotation.EnableBinding;

import org.springframework.cloud.stream.annotation.StreamListener;

import org.springframework.cloud.stream.messaging.Sink;

import org.springframework.stereotype.Service;


@Service

@EnableBinding(Sink.class)  // Mesaj tüketen bileşen olarak yapılandırma

public class MessageConsumer {


    @StreamListener(Sink.INPUT)  // Mesajları dinlemek için

    public void consumeMessage(String message) {

        System.out.println("Mesaj alındı: " + message);

    }

}



Açıklamalar:

  • @EnableBinding(Sink.class): Bu anotasyon, bir input kanalı oluşturur ve bu kanaldan mesajların alınmasını sağlar.
  • @StreamListener(Sink.INPUT): Bu anotasyon, belirtilen input kanalı üzerindeki mesajları dinler ve consumeMessage() metoduna iletir.


5. Mesajları Test Etme


Yukarıdaki yapılandırmalar ile uygulama çalıştırıldığında, bir Kafka broker’a bağlanarak mesajlar gönderilip alınır. MessageProducer sınıfındaki sendMessage() metodu ile mesajlar gönderilirken, MessageConsumer sınıfı, gönderilen mesajları dinler ve işlemlerini gerçekleştirir.


Örneğin, aşağıdaki kod ile bir mesaj gönderme işlemi yapabilirsiniz:


Message Gönderme İşlemi



import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class MessageController {


    private final MessageProducer messageProducer;


    public MessageController(MessageProducer messageProducer) {

        this.messageProducer = messageProducer;

    }


    @GetMapping("/send")

    public String sendMessage() {

        String message = "Merhaba, Spring Cloud Stream!";

        messageProducer.sendMessage(message);

        return "Mesaj gönderildi!";

    }

}



Tarayıcıda http://localhost:8080/send adresine istek yaptığınızda mesaj Kafka'ya gönderilecek ve MessageConsumer sınıfı bu mesajı dinleyerek işleyecektir.


6. Spring Cloud Stream ile RabbitMQ Kullanımı


Kafka yerine RabbitMQ kullanmak isterseniz, Spring Cloud Stream RabbitMQ entegrasyonu oldukça benzerdir. spring-cloud-starter-stream-rabbit bağımlılığını ekleyip, RabbitMQ bağlantı bilgilerini yapılandırmanız yeterlidir.


application.properties (RabbitMQ için)



spring.cloud.stream.bindings.output.destination=my-queue

spring.cloud.stream.bindings.input.destination=my-queue


spring.rabbitmq.host=localhost

spring.rabbitmq.port=5672



7. Spring Cloud Stream ile Farklı Bindingler Kullanma


Spring Cloud Stream, birden fazla giriş ve çıkış kanalı oluşturmanızı destekler. Bu sayede farklı kanallar üzerinden mesajları yönlendirebilirsiniz. Örneğin, farklı topic'lere veya kuyruklara mesaj gönderebilir ve bu mesajları dinleyebilirsiniz.


Örnek: Farklı Kanallar ile Binding



@EnableBinding({Source.class, Sink.class})

public class MultiChannelService {

    

    private final Source source;


    public MultiChannelService(Source source) {

        this.source = source;

    }


    @StreamListener(Sink.INPUT)

    public void handleInputMessage(String message) {

        System.out.println("Gelen mesaj: " + message);

    }


    public void sendOutputMessage(String message) {

        source.output().send(MessageBuilder.withPayload(message).build());

        System.out.println("Mesaj gönderildi: " + message);

    }

}



8. Spring Cloud Stream ile Fault Tolerance (Hata Toleransı)


Spring Cloud Stream, retry (tekrar deneme) ve circuit breaker (devre kesici) gibi dayanıklılık mekanizmalarını destekler. Böylece, başarısız mesajlar için tekrar denemeler yapılabilir ve sistemin çökmesi engellenir.


Özet:


  • Spring Cloud Stream, Spring Boot ile uygulamalar arasında mesajlaşma sağlayan bir framework'tür.
  • Kafka ve RabbitMQ gibi mesajlaşma sistemleri ile kolayca entegre olabilir ve mesaj alışverişi yapabilirsiniz.
  • Mesajlar, producer ve consumer yapıları ile işlenir ve Spring Cloud Stream kanalları (bindings) aracılığıyla yönlendirilir.

-

57. WebSocket Kullanımı

  • WebSocket ile gerçek zamanlı haberleşme sağlayın:

  •   @Configuration
  •   @EnableWebSocketMessageBroker
  •   public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
  •       @Override
  •       public void configureMessageBroker(MessageBrokerRegistry config) {
  •           config.enableSimpleBroker("/topic");
  •           config.setApplicationDestinationPrefixes("/app");
  •       }
  •   
  •       @Override
  •       public void registerStompEndpoints(StompEndpointRegistry registry) {
  •           registry.addEndpoint("/websocket").withSockJS();
  •       }
  •   }

WebSocket, istemci ve sunucu arasında çift yönlü, gerçek zamanlı bir iletişim kanalı sağlayan bir protokoldür. Spring Boot, STOMP (Simple Text Oriented Messaging Protocol) üzerine kurulmuş bir WebSocket mesajlaşma desteği sunar. Bu özellik, kullanıcılarla gerçek zamanlı etkileşim gerektiren uygulamalar (örneğin, chat uygulamaları, canlı veri akışı, bildirimler) için idealdir.


Spring Boot'ta WebSocket Kullanımı


WebSocket'ler Spring Boot uygulamanızda kolayca entegre edilebilir. Aşağıda, WebSocket yapılandırması ve kullanımına yönelik adım adım bir rehber bulabilirsiniz.


1. WebSocket Yapılandırması


Spring Boot'ta WebSocket desteğini etkinleştirmek için bir yapılandırma sınıfı oluşturmanız gerekir. Bu sınıf, WebSocket protokolünü etkinleştirecek ve mesaj yönlendirme yapılarını (message broker) ayarlayacaktır.


Adım 1: WebSocket Konfigürasyonu



import org.springframework.context.annotation.Configuration;

import org.springframework.messaging.simp.config.MessageBrokerRegistry;

import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;

import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;


@Configuration

@EnableWebSocketMessageBroker

public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {


    @Override

    public void configureMessageBroker(MessageBrokerRegistry config) {

        // Mesajları iletecek bir broker tanımlanıyor

        config.enableSimpleBroker("/topic");

        // Uygulamanın endpoint'leri için bir prefix belirleniyor

        config.setApplicationDestinationPrefixes("/app");

    }


    @Override

    public void registerStompEndpoints(StompEndpointRegistry registry) {

        // WebSocket bağlantı noktası tanımlanıyor ve SockJS destekleniyor

        registry.addEndpoint("/websocket").withSockJS();

    }

}



Yukarıdaki yapılandırmada:

  • @EnableWebSocketMessageBroker: Spring Boot uygulamanızda WebSocket mesajlaşma desteğini etkinleştirir.
  • configureMessageBroker: Mesaj iletimi için bir broker tanımlar. Burada /topic ön ekine sahip olan tüm mesajlar broker tarafından yönlendirilir.
  • setApplicationDestinationPrefixes: Uygulama tarafından işlenecek mesajlar için bir prefix ayarlanır. Örneğin, /app ile başlayan mesajlar işlenmek üzere sunucuya gönderilir.
  • registerStompEndpoints: WebSocket bağlantısı kurulacak URL ve SockJS desteği ayarlanır. SockJS, WebSocket'in desteklenmediği tarayıcılarda alternatif bir iletişim yöntemi olarak kullanılabilir.


2. Controller ve Mesaj Gönderimi


WebSocket üzerinden mesaj alışverişi yapabilmek için bir @Controller sınıfı tanımlanması gerekir. Bu sınıf, gelen WebSocket mesajlarını dinler ve bunları işleyerek ilgili istemcilere gönderir.


Adım 2: WebSocket Kontrolcüsü



import org.springframework.messaging.handler.annotation.MessageMapping;

import org.springframework.messaging.handler.annotation.SendTo;

import org.springframework.stereotype.Controller;


@Controller

public class WebSocketController {


    @MessageMapping("/hello")

    @SendTo("/topic/greetings")

    public String sendMessage(String message) throws Exception {

        // İstek geldiğinde 1 saniye gecikme ile yanıt dönelim

        Thread.sleep(1000);

        return "Hello, " + message + "!";

    }

}



  • @MessageMapping: İstemcilerden gelen WebSocket mesajlarını dinler. Burada, /app/hello yolu dinlenir.
  • @SendTo: Sunucu tarafından işlendikten sonra ilgili mesajı bir topic'e yönlendirir. İlgili mesaj, bu topic'i dinleyen tüm istemcilere iletilir.


3. Frontend (JavaScript) ile WebSocket Bağlantısı


WebSocket bağlantısını kurmak ve istemci tarafından mesaj göndermek için bir HTML dosyasına JavaScript ekleyerek WebSocket istemcisi yazabilirsiniz.


Adım 3: HTML ve JavaScript



<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebSocket Example</title>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.0/sockjs.min.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

    <script>

        var stompClient = null;


        function connect() {

            var socket = new SockJS('/websocket');

            stompClient = Stomp.over(socket);

            stompClient.connect({}, function (frame) {

                console.log('Connected: ' + frame);

                stompClient.subscribe('/topic/greetings', function (greeting) {

                    showGreeting(JSON.parse(greeting.body).content);

                });

            });

        }


        function sendMessage() {

            var name = document.getElementById("name").value;

            stompClient.send("/app/hello", {}, name);

        }


        function showGreeting(message) {

            var response = document.getElementById("response");

            response.innerHTML += "<tr><td>" + message + "</td></tr>";

        }

    </script>

</head>

<body onload="connect()">

    <div>

        <input type="text" id="name" placeholder="Enter your name">

        <button onclick="sendMessage()">Send</button>

    </div>

    <table>

        <tr>

            <th>Responses:</th>

        </tr>

        <tbody id="response"></tbody>

    </table>

</body>

</html>



Bu basit frontend uygulamasında:

  • connect(): WebSocket bağlantısını kurar ve /topic/greetings topic'ini dinler.
  • sendMessage(): İstemciden sunucuya /app/hello adresine mesaj gönderir.
  • showGreeting(): Gelen yanıtları ekranda gösterir.


4. Uygulamayı Test Etme


  • Spring Boot uygulamanızı başlattıktan sonra, tarayıcıda hazırladığınız HTML dosyasını açın.
  • Bir isim girip "Send" butonuna bastığınızda, sunucuya mesaj gönderilecek ve yanıt olarak "Hello, {name}!" mesajı alacaksınız.
  • İlgili mesajlar tüm bağlı istemcilere gönderilecektir.


5. Sonuç


Bu adımlar ile Spring Boot uygulamanızda WebSocket kullanarak gerçek zamanlı iletişim sağlayabilirsiniz. WebSocket, özellikle canlı bildirimler, chat uygulamaları, finansal veri akışı gibi gerçek zamanlı etkileşim gerektiren uygulamalarda büyük fayda sağlar. SockJS desteği ile WebSocket'i desteklemeyen tarayıcılar için de sorunsuz bir çözüm sunmuş olursunuz.

58. GraphQL ile Veri Yönetimi

  • GraphQL kullanarak REST'e alternatif bir veri yönetimi katmanı oluşturun:

  •   <dependency>
  •       <groupId>com.graphql-java-kickstart</groupId>
  •       <artifactId>graphql-spring-boot-starter</artifactId>
  •   </dependency>

58. GraphQL ile Veri Yönetimi

GraphQL, REST API'lere alternatif olarak kullanılan esnek ve verimli bir veri sorgulama dili ve yürütme ortamıdır. REST API'lerinden farklı olarak, GraphQL, istemcilerin yalnızca ihtiyaç duydukları veriyi almasını sağlar ve veri fazlalığını veya çok sayıda istek yapma ihtiyacını azaltır. GraphQL ile veri sorgulama, mutasyon (veri ekleme/güncelleme/silme), ve abonelik (subscriptions) işlemleri kolayca yapılabilir.


Adım Adım Spring Boot ile GraphQL Entegrasyonu


  1. GraphQL Bağımlılığını Ekleyin:
  2. Spring Boot projesine GraphQL entegrasyonu yapmak için pom.xml dosyasına aşağıdaki bağımlılığı ekleyin:


  3.    <dependency>
  4.        <groupId>com.graphql-java-kickstart</groupId>
  5.        <artifactId>graphql-spring-boot-starter</artifactId>
  6.    </dependency>
  7.    <dependency>
  8.        <groupId>com.graphql-java-kickstart</groupId>
  9.        <artifactId>graphql-java-tools</artifactId>
  10.    </dependency>


  11. Bu bağımlılıklar, GraphQL ile Spring Boot uygulamasını kolayca entegre etmenizi sağlar. graphql-spring-boot-starter temel GraphQL desteğini eklerken, graphql-java-tools GraphQL şemalarını ve çözücülerini (resolvers) yapılandırmak için kullanılır.

  12. GraphQL Şemasını Tanımlayın:
  13. GraphQL, bir şema tanımlaması ile çalışır. Bu şema, uygulamanızda hangi veri tiplerinin sorgulanabileceğini ve hangi operasyonların yapılabileceğini belirler. src/main/resources/graphql/ dizininde schema.graphqls adında bir dosya oluşturun.

  14. Aşağıda basit bir şema örneği yer alıyor:


  15.    type Query {
  16.        getBookById(id: ID!): Book
  17.        allBooks: [Book]
  18.    }
  19.    
  20.    type Mutation {
  21.        addBook(title: String!, author: String!): Book
  22.    }
  23.    
  24.    type Book {
  25.        id: ID!
  26.        title: String!
  27.        author: String!
  28.    }


    • Query: Verilerin sorgulandığı operasyonları tanımlar.
    • Mutation: Veri ekleme, güncelleme veya silme işlemleri yapılır.
    • Book: Bir kitap nesnesi, GraphQL şeması ile temsil edilir.


  1. Model Sınıfını Yazın:
  2. GraphQL'de tanımladığınız veri türlerini temsil edecek model sınıflarını oluşturun. Örneğin, yukarıdaki GraphQL şeması için bir Book sınıfı oluşturabilirsiniz:


  3.    public class Book {
  4.        private String id;
  5.        private String title;
  6.        private String author;
  7.    
  8.        // Constructors, Getters and Setters
  9.    }


  10. GraphQL Query ve Mutation Çözücülerini Yazın:
  11. Şemada tanımladığınız Query ve Mutation işlemlerini çözecek (handle edecek) sınıfları yazmanız gerekir. Book için bir Query ve Mutation sınıfı şu şekilde olabilir:


  12.    import com.coxautodev.graphql.tools.GraphQLQueryResolver;
  13.    import org.springframework.stereotype.Component;
  14.    
  15.    import java.util.ArrayList;
  16.    import java.util.List;
  17.    
  18.    @Component
  19.    public class BookQueryResolver implements GraphQLQueryResolver {
  20.    
  21.        private List<Book> books = new ArrayList<>();
  22.    
  23.        public BookQueryResolver() {
  24.            books.add(new Book("1", "GraphQL Basics", "John Doe"));
  25.            books.add(new Book("2", "Spring Boot with GraphQL", "Jane Smith"));
  26.        }
  27.    
  28.        public Book getBookById(String id) {
  29.            return books.stream()
  30.                    .filter(book -> book.getId().equals(id))
  31.                    .findFirst()
  32.                    .orElse(null);
  33.        }
  34.    
  35.        public List<Book> allBooks() {
  36.            return books;
  37.        }
  38.    }


  39. Aynı şekilde, bir Mutation sınıfı da şöyle olabilir:


  40.    import com.coxautodev.graphql.tools.GraphQLMutationResolver;
  41.    import org.springframework.stereotype.Component;
  42.    
  43.    @Component
  44.    public class BookMutationResolver implements GraphQLMutationResolver {
  45.    
  46.        private List<Book> books = new ArrayList<>();
  47.    
  48.        public Book addBook(String title, String author) {
  49.            Book newBook = new Book(String.valueOf(books.size() + 1), title, author);
  50.            books.add(newBook);
  51.            return newBook;
  52.        }
  53.    }


    • GraphQLQueryResolver: GraphQL sorgularını yöneten çözücü.
    • GraphQLMutationResolver: Mutasyonları (değişiklik, ekleme vb.) yöneten çözücü.


  1. Spring Boot Yapılandırmasını Yapın:
  2. application.properties dosyanıza GraphQL'i çalıştıracak yapılandırmaları ekleyebilirsiniz. Temel GraphQL yapılandırması için ek bir ayar yapmanıza gerek olmasa da, özel ihtiyaçlar için şu ayarları ekleyebilirsiniz:


  3.    graphql.servlet.mapping=/graphql
  4.    graphql.servlet.enabled=true
  5.    graphql.tools.schema-location=classpath:graphql/schema.graphqls


  6. Bu ayarlarla GraphQL endpoint'ini /graphql olarak belirleyebilir ve schema.graphqls dosyasının doğru yerde olduğundan emin olabilirsiniz.

  7. GraphQL Endpoint'i Test Edin:
  8. Uygulamanız çalıştıktan sonra, GraphQL endpoint’ini test etmek için Postman veya benzeri bir araç kullanabilirsiniz. Alternatif olarak, GraphiQL adlı web tabanlı bir arayüzle sorgularınızı test edebilirsiniz.

  9. Örnek GraphQL sorguları:


  10.    {
  11.        allBooks {
  12.            id
  13.            title
  14.            author
  15.        }
  16.    }


  17. Bu sorgu, tüm kitapları listeleyecektir. Aynı şekilde, bir mutasyon (ekleme işlemi) yapabilirsiniz:


  18.    mutation {
  19.        addBook(title: "New Book", author: "New Author") {
  20.            id
  21.            title
  22.        }
  23.    }


  24. Bu mutasyon, yeni bir kitap ekleyecek ve eklenen kitabın id ve title değerlerini döndürecektir.


Özet


  • GraphQL, veri sorgulama ve yönetiminde esneklik ve verimlilik sağlayan REST’e alternatif bir yaklaşımdır.
  • Spring Boot ile GraphQL, uygulamanızda daha esnek veri çekme işlemleri yapmanıza olanak tanır.
  • Query ve Mutation çözücülerini kullanarak veri işlemlerini kolayca yönetebilir, istemcilerin gereksiz veri çekme işlemlerini engelleyebilirsiniz.

  

Bu yapıyı kullanarak daha optimize ve istemci odaklı API'lar geliştirebilirsiniz.

59. Spring Data REST Kullanımı

  • Spring Data REST ile JPA repository'lerinizi otomatik olarak REST API'lere dönüştürün:

  •   <dependency>
  •       <groupId>org.springframework.boot</groupId>
  •       <artifactId>spring-boot-starter-data-rest</artifactId>
  •   </dependency>

Spring Data REST Kullanımı


Spring Data REST, JPA repository'lerini otomatik olarak RESTful web servislerine dönüştüren bir araçtır. Bu araç, veritabanındaki varlıkları (entity) hızlı bir şekilde HTTP istekleriyle yönetmenizi sağlar. Yani, veritabanı işlemleri için elle REST endpoint'leri yazmanıza gerek kalmaz; Spring Data REST sizin için bu işlemleri otomatik olarak halleder.


Adım Adım Spring Data REST Kullanımı


1. Bağımlılıklar

Spring Data REST kullanmak için proje yapılandırmanıza gerekli bağımlılığı ekleyin. pom.xml dosyanıza şu bağımlılığı ekleyin:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-rest</artifactId>

</dependency>



Eğer Gradle kullanıyorsanız, aşağıdaki bağımlılığı build.gradle dosyanıza ekleyin:



implementation 'org.springframework.boot:spring-boot-starter-data-rest'



2. Entity Tanımlama

Spring Data REST'in otomatik olarak API oluşturabilmesi için önce bir entity tanımlamanız gerekir. Örneğin, basit bir Product entity sınıfı aşağıdaki gibi olabilir:



import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;


@Entity

public class Product {


    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    private Long id;


    private String name;

    private Double price;


    // Getter ve Setter'lar

    public Long getId() {

        return id;

    }


    public void setId(Long id) {

        this.id = id;

    }


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public Double getPrice() {

        return price;

    }


    public void setPrice(Double price) {

        this.price = price;

    }

}



3. Repository Tanımlama

Spring Data REST, JPA repository'lerinizi otomatik olarak REST API'lerine dönüştürdüğü için, veritabanı işlemleri için bir repository tanımlamanız gerekir:



import org.springframework.data.jpa.repository.JpaRepository;


public interface ProductRepository extends JpaRepository<Product, Long> {

}



Bu ProductRepository tanımlamasıyla, Spring Data REST Product entity'si için CRUD işlemlerini gerçekleştirebileceğiniz REST endpoint'lerini otomatik olarak oluşturacaktır.


4. Uygulamanızı Başlatma

Spring Boot uygulamanızı başlattığınızda, Spring Data REST sizin için şu otomatik REST endpoint'lerini oluşturur:


  • GET /products – Tüm ürünleri listeler.
  • GET /products/{id} – Belirtilen id ile bir ürünü getirir.
  • POST /products – Yeni bir ürün oluşturur.
  • PUT /products/{id} – Var olan bir ürünü günceller.
  • DELETE /products/{id} – Belirtilen id ile ürünü siler.


5. Örnek HTTP İstekleri

Oluşturulan otomatik API'yi test edebilirsiniz. İşte bazı örnek HTTP istekleri:


  • Tüm Ürünleri Listeleme (GET):

  •   GET http://localhost:8080/products


  • Bir Ürün Getirme (GET):

  •   GET http://localhost:8080/products/1


  • Yeni Ürün Oluşturma (POST):

  •   POST http://localhost:8080/products
  •   {
  •     "name": "Laptop",
  •     "price": 1500.00
  •   }


  • Bir Ürünü Güncelleme (PUT):

  •   PUT http://localhost:8080/products/1
  •   {
  •     "name": "Updated Laptop",
  •     "price": 1600.00
  •   }


  • Bir Ürünü Silme (DELETE):

  •   DELETE http://localhost:8080/products/1


6. İlişkili Varlıklar

Spring Data REST, ilişkili varlıklar ile çalışmayı da destekler. Örneğin, bir Category entity'si ekleyip her ürünün bir kategoriye ait olmasını sağlayabilirsiniz. Spring Data REST, bu tür ilişkileri otomatik olarak REST API'lerine dönüştürür.



@Entity

public class Category {


    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    private Long id;


    private String name;


    // Getter ve Setter'lar

}



Ve Product entity'sine bir ilişki ekleyin:



@ManyToOne

private Category category;



Bu ilişkili verileri de Spring Data REST aracılığıyla otomatik olarak yönetebilirsiniz.


7. Spring Data REST Özelleştirme

Spring Data REST, isteklerinizi özelleştirmenize de izin verir. Örneğin, belirli alanları gizleyebilir veya belirli bir alanın sadece okunabilir olmasını sağlayabilirsiniz. Bunun için @RestResource, @JsonIgnore, ve @RepositoryRestResource gibi anotasyonlar kullanılabilir.



@Entity

public class Product {


    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    private Long id;


    private String name;


    @JsonIgnore

    private Double price;


    // Getter ve Setter'lar

}



Yukarıdaki örnekte price alanı API yanıtında gizlenecektir.


Sonuç


Spring Data REST, JPA repository'lerinizin üzerine hızla RESTful API'ler oluşturmanıza olanak tanıyan güçlü bir araçtır. Sadece bir kaç konfigürasyon ve anotasyon ile CRUD işlemlerini kolayca gerçekleştirebilirsiniz. Özellikle hızlı prototipleme veya basit CRUD tabanlı projelerde oldukça faydalıdır.

60. OAuth2 ile Kimlik Doğrulama

  • OAuth2 kullanarak kullanıcı kimlik doğrulama ve yetkilendirme işlemlerini yönetin:

  •   <dependency>
  •       <groupId>org.springframework.boot</groupId>
  •       <artifactId>spring-boot-starter-oauth2-client</artifactId>
  •   </dependency>

60. OAuth2 ile Kimlik Doğrulama


OAuth2, kullanıcı kimlik doğrulama ve yetkilendirme işlemleri için kullanılan yaygın bir protokoldür. OAuth2, kullanıcıların bir uygulama veya servise erişmesini sağlarken, bu işlemleri güvenli bir şekilde yönetir. Spring Boot, OAuth2 protokolünü kullanarak uygulamalarınızı güvence altına almanızı sağlar ve OAuth2 Client ile sosyal medya hesapları (Google, Facebook) gibi üçüncü parti sağlayıcılarla entegrasyon yapabilirsiniz.


Aşağıda, Spring Boot uygulamalarında OAuth2 ile kullanıcı kimlik doğrulama ve yetkilendirme işlemlerini nasıl yönetebileceğinizi anlatıyorum.


1. OAuth2 Nedir?


OAuth2 (Open Authorization), kullanıcıların kimlik doğrulama ve yetkilendirme işlemlerini güvenli bir şekilde gerçekleştirmelerini sağlayan bir protokoldür. OAuth2 kullanarak bir uygulama, kullanıcıdan kimlik doğrulama yapmasını isteyebilir ve bu kimlik doğrulama işlemi başka bir yetkili servis tarafından yapılır. OAuth2 sürecinde uygulama, kimlik sağlayıcıdan (Identity Provider) bir erişim yetkisi (token) alır ve bu token ile kullanıcıyı yetkilendirir.


2. Spring Boot'ta OAuth2 Yapılandırması


Spring Boot projelerinde OAuth2 kullanarak kimlik doğrulama işlemi yapmak için gerekli bağımlılıkları ekleyip, yapılandırmayı ayarlayabilirsiniz.


Adım 1: Bağımlılıkları Ekleyin


Spring Boot projenize spring-boot-starter-oauth2-client bağımlılığını ekleyin. Bu bağımlılık, OAuth2 kimlik doğrulama ve yetkilendirme işlemlerini yönetmek için gerekli olan bileşenleri sağlar.


pom.xml



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-oauth2-client</artifactId>

</dependency>



Adım 2: application.properties ile OAuth2 Ayarları


OAuth2 sağlayıcısı ile entegrasyon yapmak için gerekli yapılandırmaları application.properties dosyasına ekleyin. Aşağıda bir Google OAuth2 entegrasyonu örneği yer almaktadır.


application.properties



spring.security.oauth2.client.registration.google.client-id=GOOGLE_CLIENT_ID

spring.security.oauth2.client.registration.google.client-secret=GOOGLE_CLIENT_SECRET

spring.security.oauth2.client.registration.google.scope=profile, email

spring.security.oauth2.client.registration.google.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}


spring.security.oauth2.client.provider.google.authorization-uri=https://accounts.google.com/o/oauth2/auth

spring.security.oauth2.client.provider.google.token-uri=https://oauth2.googleapis.com/token

spring.security.oauth2.client.provider.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo

spring.security.oauth2.client.provider.google.user-name-attribute=sub



Açıklamalar:

  • spring.security.oauth2.client.registration.google.client-id: Google API tarafından sağlanan client ID.
  • spring.security.oauth2.client.registration.google.client-secret: Google API tarafından sağlanan client secret.
  • spring.security.oauth2.client.registration.google.scope: OAuth2 işlemi sırasında istenen erişim izinleri (kullanıcı profili ve e-posta bilgileri gibi).
  • authorization-uri, token-uri, ve user-info-uri: Google OAuth2 endpoint'leri.


Adım 3: Güvenlik Konfigürasyonu


OAuth2 işlemlerini yönetmek için Spring Security'yi konfigüre etmemiz gerekir. WebSecurityConfigurerAdapter sınıfını genişleterek güvenlik yapılandırmasını yapabilirsiniz.


SecurityConfig.java



import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;


@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Override

    protected void configure(HttpSecurity http) throws Exception {

        http

            .authorizeRequests()

                .antMatchers("/", "/login**").permitAll()  // Ana sayfa ve login sayfasına herkes erişebilir

                .anyRequest().authenticated()  // Diğer tüm istekler kimlik doğrulaması gerektirir

            .and()

            .oauth2Login()  // OAuth2 tabanlı kimlik doğrulama

                .defaultSuccessUrl("/home", true);  // Başarılı giriş sonrası yönlendirilecek sayfa

    }

}



Açıklamalar:

  • .antMatchers("/", "/login").permitAll()**: Ana sayfa ve login URL'lerine kimlik doğrulaması yapılmadan erişilebilir.
  • .anyRequest().authenticated(): Diğer tüm URL'ler kimlik doğrulaması gerektirir.
  • .oauth2Login(): OAuth2 tabanlı giriş işlemleri devreye alınır.
  • .defaultSuccessUrl("/home", true): Kullanıcı başarıyla giriş yaptığında /home sayfasına yönlendirilir.


3. OAuth2 ile Giriş İşlemi


OAuth2 entegrasyonunu tamamladıktan sonra, uygulamanıza gelen kullanıcılar OAuth2 sağlayıcısı (örneğin Google) üzerinden kimlik doğrulaması yapabilirler. Bu işlem sırasında kullanıcı, Google üzerinden oturum açar ve uygulama, Google'dan bir erişim token'ı alarak kullanıcıyı doğrular.


Uygulamanızda OAuth2 ile doğrulanmış bir kullanıcı oturumu açtıktan sonra kullanıcının kimlik bilgilerini alabilir ve uygulama içi yetkilendirme işlemlerini yapabilirsiniz.


4. Kullanıcı Bilgilerine Erişim


Kullanıcı başarılı bir şekilde OAuth2 ile giriş yaptıktan sonra kullanıcı bilgilerine erişmek isteyebilirsiniz. Spring Security, bu bilgileri OAuth2AuthenticationToken veya OAuth2User sınıfı aracılığıyla sağlar.


HomeController.java



import org.springframework.security.core.annotation.AuthenticationPrincipal;

import org.springframework.security.oauth2.core.oidc.user.OidcUser;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.GetMapping;


@Controller

public class HomeController {


    @GetMapping("/home")

    public String home(@AuthenticationPrincipal OidcUser oidcUser, Model model) {

        model.addAttribute("user", oidcUser);

        return "home";

    }

}



Açıklamalar:

  • @AuthenticationPrincipal OidcUser: Giriş yapan kullanıcının OAuth2 kullanıcı bilgilerini alır.
  • oidcUser: Kullanıcının profil bilgileri, e-posta gibi bilgilere erişmenizi sağlar.


5. Kullanıcı Bilgilerini Görüntüleme


Yukarıdaki kontrolcü, kullanıcı bilgilerini home.html adlı bir şablona gönderir. Bu şablon içerisinde kullanıcı bilgilerini görüntüleyebilirsiniz.


home.html



<!DOCTYPE html>

<html>

<head>

    <title>Home Page</title>

</head>

<body>

    <h1>Hoş geldiniz, ${user.name}!</h1>

    <p>E-posta: ${user.email}</p>

    <p>Profil Resmi: <img src="${user.picture}" alt="Profile Picture"></p>

</body>

</html>



Bu sayfada kullanıcının adı, e-posta adresi ve profil resmi görüntülenir.


6. OAuth2 ile Yetkilendirme İşlemleri


Spring Security, OAuth2 ile yetkilendirme işlemleri yapmak için kullanıcı rollerini ve izinlerini destekler. Kullanıcının rolüne bağlı olarak belirli işlemlere izin verebilir veya kısıtlamalar getirebilirsiniz.



http

    .authorizeRequests()

        .antMatchers("/admin/**").hasRole("ADMIN")

        .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")

        .anyRequest().authenticated();



Bu yapılandırma, /admin URL'sine yalnızca ADMIN rolüne sahip kullanıcıların erişmesine izin verirken, /user URL'sine hem USER hem de ADMIN rollerine sahip kullanıcıların erişmesine izin verir.


7. OAuth2 ile Token Yönetimi


OAuth2 kullanarak giriş yapan bir kullanıcının erişim token'ı Spring Security tarafından yönetilir. Token, kimlik doğrulama ve yetkilendirme işlemleri için kullanılır. Ayrıca refresh token kullanarak token'ın süresi dolduğunda otomatik yenileme işlemi yapılabilir.


Özet:


  • OAuth2 protokolü ile Spring Boot projelerinde kullanıcı kimlik doğrulama ve yetkilendirme işlemleri güvenli bir şekilde yönetilebilir.
  • Spring Boot, OAuth2 Client desteği ile Google, Facebook gibi sağlayıcılarla kolayca entegre olabilir.
  • Kullanıcı bilgileri OAuth2User veya OidcUser ile alınabilir ve uygulama içinde kullanılabilir.
  • OAuth2 ile uygulamanızın güvenliğini artırabilir, kullanıcı kimlik doğrulama işlemlerini merkezi bir yerden yönetebilirsiniz.


Bu yapı, özellikle mikroservis tabanlı projelerde veya sosyal medya hesaplarıyla oturum açmayı destekleyen uygulamalarda oldukça faydal

61. Session Yönetimi

  • Kullanıcı oturumlarını (session) yönetmek için Spring Session ve Redis kullanın:

  •   <dependency>
  •       <groupId>org.springframework.session</groupId>
  •       <artifactId>spring-session-data-redis</artifactId>
  •   </dependency>

Spring Session, kullanıcı oturumlarının (session) merkezi bir yerde yönetilmesine olanak tanıyan bir kütüphanedir. Spring Session, genellikle Redis gibi bir veri deposu ile kullanılarak, oturum yönetimini dağıtık sistemler ve mikroservisler gibi yapıların ihtiyaçlarına uygun hale getirir. Bu yapı, uygulamaların yatayda ölçeklenebilmesini ve oturum verilerinin uygulama sunucularından bağımsız bir yerde tutulmasını sağlar. Redis, hızlı bir şekilde veriye erişim sağlayarak oturum verilerinin merkezi bir yerde tutulması için ideal bir araçtır.


1. Spring Session ve Redis Kullanımı


Spring Boot uygulamanızda Spring Session ve Redis kullanarak oturum yönetimini yapılandırabilirsiniz. Aşağıda bu yapılandırmanın nasıl yapılacağı adım adım açıklanmıştır.


Adım 1: Spring Session ve Redis Bağımlılıklarını Ekleyin


İlk olarak, Spring Session ve Redis entegrasyonu için gerekli bağımlılıkları projenize eklemeniz gerekiyor.


Maven:



<dependency>

    <groupId>org.springframework.session</groupId>

    <artifactId>spring-session-data-redis</artifactId>

</dependency>


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>



Gradle:



implementation 'org.springframework.session:spring-session-data-redis'

implementation 'org.springframework.boot:spring-boot-starter-data-redis'



Adım 2: Redis Kurulumu ve Yapılandırması


Redis’i sisteminizde çalıştırmanız gerekiyor. Redis’i Docker ile hızlıca kurabilirsiniz:



docker run -d -p 6379:6379 redis



Redis, 6379 portunda çalışmaya başlayacak ve Spring Boot uygulamanız Redis’e bağlanarak oturum verilerini orada saklayacak.


Adım 3: Spring Boot Uygulamanızda Redis Yapılandırması


Spring Boot uygulamanızın application.properties ya da application.yml dosyasına Redis ile ilgili yapılandırmayı ekleyin.


application.properties:



# Redis bağlantısı

spring.redis.host=localhost

spring.redis.port=6379


# Oturum zaman aşımı (dakika olarak)

server.servlet.session.timeout=30m



Bu yapılandırma, Redis sunucusuna bağlanmak için gerekli bilgileri sağlar ve oturum süresini 30 dakika olarak belirler.


Adım 4: Spring Session Yapılandırması


Spring Session'ın Redis ile kullanılabilmesi için ekstra bir yapılandırmaya ihtiyaç yoktur, çünkü spring-session-data-redis bağımlılığı zaten tüm gerekli yapılandırmayı otomatik olarak sağlar. Ancak, oturum id'lerinin Redis’te nasıl yönetileceğine dair belirli ayarlamalar yapabilirsiniz.


Spring Boot uygulamasında Redis tabanlı oturum yönetimi etkinleştirilmiş olur ve Redis'te saklanan oturumlar şu yapıda tutulur:


  • Her bir oturum için bir Redis anahtarı oluşturulur.
  • Oturum süreleri Redis'te anahtarın süresi olarak takip edilir.


Adım 5: Session Kullanımı


Spring Session, uygulamanızdaki oturumları Spring’in standart HttpSession API'si ile yönetmenize olanak tanır. Oturumları kullanmak için ekstra bir kod yazmanıza gerek kalmaz. Örneğin, aşağıdaki gibi bir kontrolcüde kullanıcı bilgilerini oturumda saklayabilirsiniz:



import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.SessionAttributes;

import org.springframework.web.bind.annotation.RestController;


import javax.servlet.http.HttpSession;


@RestController

@RequestMapping("/session")

public class SessionController {


    @GetMapping("/set")

    public String setSession(HttpSession session) {

        session.setAttribute("username", "Eda");

        return "Session data set!";

    }


    @GetMapping("/get")

    public String getSession(HttpSession session) {

        String username = (String) session.getAttribute("username");

        return username != null ? "Session data: " + username : "No session data found";

    }

}



Bu örnekte, /session/set endpoint'i kullanılarak username değeri oturuma kaydedilir. /session/get endpoint'i ile de bu oturum verisi geri alınır. Oturum verileri Redis üzerinde saklanır ve Redis'i kapatıp açtığınızda bu verilere erişmeye devam edersiniz.


Adım 6: Redis’teki Oturum Verilerinin İncelenmesi


Redis’e oturum verilerinin başarıyla yazıldığını görmek için, terminalden Redis CLI'yi başlatabilir ve oturum anahtarlarını inceleyebilirsiniz.



redis-cli

KEYS *



Bu komut, Redis'te saklanan tüm anahtarları listeleyecektir. Oturum verileri genellikle spring:session:sessions prefiksiyle saklanır.


Adım 7: Oturum Süresinin Yönetimi


Spring Session ile oturum süresini kolayca yönetebilirsiniz. application.properties dosyasında oturumun zaman aşımı süresini ayarlayarak belirli bir süre boyunca kullanılmayan oturumların otomatik olarak silinmesini sağlayabilirsiniz.



server.servlet.session.timeout=30m



Bu ayar, oturumun 30 dakika boyunca inaktif kaldığında zaman aşımına uğrayacağını belirtir. Bu süre dolduğunda, oturum verileri Redis'ten otomatik olarak silinir.


Sonuç


Bu adımlar ile Spring Boot uygulamanızda Spring Session ve Redis kullanarak merkezi bir oturum yönetimi kurabilirsiniz. Bu yapı özellikle dağıtık sistemlerde veya mikroservis mimarilerinde kullanışlıdır. Kullanıcı oturumları Redis'te saklanarak, uygulamalarınız arasında oturum verilerinin paylaşılmasını ve merkezi yönetilmesini sağlar. Redis gibi hızlı bir veritabanı kullanılması, yüksek performanslı oturum yönetimi sağlar.

62. Spring Boot ile Redis Cache

  • Redis kullanarak önbellekleme yapın:

  •   @Bean
  •   public RedisTemplate<String, Object> redisTemplate() {
  •       RedisTemplate<String, Object> template = new RedisTemplate<>();
  •       template.setConnectionFactory(redisConnectionFactory());
  •       return template;
  •   }

62. Spring Boot ile Redis Cache


Redis, yüksek performanslı ve dağıtık bir veri deposu olup genellikle önbellekleme (caching) amacıyla kullanılır. Spring Boot, Redis ile kolayca entegre olabilen önbellekleme yeteneklerine sahiptir. Redis'i Spring Boot uygulamanıza dahil ederek veritabanı sorgularını önbelleğe alabilir, performans ve hız kazancı sağlayabilirsiniz.


Adım Adım Spring Boot ile Redis Entegrasyonu


  1. Redis Bağımlılığını Ekleyin:
  2. Spring Boot projesine Redis desteği eklemek için pom.xml dosyanıza aşağıdaki bağımlılığı ekleyin:


  3.    <dependency>
  4.        <groupId>org.springframework.boot</groupId>
  5.        <artifactId>spring-boot-starter-data-redis</artifactId>
  6.    </dependency>


  7. Bu bağımlılık, Spring Boot ve Redis entegrasyonu için gerekli sınıfları ve yapılandırmaları sağlar.

  8. Redis Server’ı Başlatın:
  9. Redis sunucusunu yerel makinenizde çalıştırmanız gerekir. Redis'i Docker ile hızlıca başlatabilirsiniz:


  10.    docker run -d -p 6379:6379 redis


  11. Bu komut, Redis'i 6379 portunda çalıştırır.

  12. Redis Yapılandırması:
  13. Redis'in uygulamanızla bağlantı kurabilmesi için application.properties veya application.yml dosyasına yapılandırmalar ekleyin. Örnek bir application.properties yapılandırması şu şekildedir:


  14.    spring.redis.host=localhost
  15.    spring.redis.port=6379


  16. Redis sunucusuna bağlanmak için gerekli ayarları burada belirleyebilirsiniz. Redis başka bir makinede çalışıyorsa, ilgili IP adresini ve port numarasını değiştirebilirsiniz.

  17. RedisTemplate Tanımlayın:
  18. Redis ile çalışmak için bir RedisTemplate bean’i tanımlayabilirsiniz. Bu template, Redis ile veri alışverişini sağlar. Aşağıda örnek bir RedisTemplate bean tanımı yer almakta:


  19.    import org.springframework.context.annotation.Bean;
  20.    import org.springframework.data.redis.connection.RedisConnectionFactory;
  21.    import org.springframework.data.redis.core.RedisTemplate;
  22.    import org.springframework.data.redis.serializer.StringRedisSerializer;
  23.    import org.springframework.stereotype.Component;
  24.    
  25.    @Component
  26.    public class RedisConfig {
  27.    
  28.        @Bean
  29.        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
  30.            RedisTemplate<String, Object> template = new RedisTemplate<>();
  31.            template.setConnectionFactory(redisConnectionFactory);
  32.            template.setKeySerializer(new StringRedisSerializer());
  33.            template.setValueSerializer(new StringRedisSerializer());
  34.            return template;
  35.        }
  36.    }


    • RedisTemplate: Redis ile veri yazma ve okuma işlemlerini yapar. Key ve Value için serileştiriciler kullanarak verilerin nasıl saklanacağını belirleyebilirsiniz.


  1. Önbellekleme Yapılandırmasını Aktif Edin:
  2. Spring Boot'ta Redis’i önbellek olarak kullanmak için uygulamanıza @EnableCaching anotasyonunu eklemeniz gerekir. Önbellekleme işlemlerini kullanmak için aşağıdaki gibi bir yapılandırma yapabilirsiniz:


  3.    import org.springframework.cache.annotation.EnableCaching;
  4.    import org.springframework.context.annotation.Configuration;
  5.    
  6.    @Configuration
  7.    @EnableCaching
  8.    public class CacheConfig {
  9.        // Cache yapılandırması
  10.    }


  11. Önbellek Anotasyonları ile Metodları Ön Belleğe Alın:
  12. Redis'i önbellek olarak kullanmak için ilgili servis metotlarına @Cacheable, @CachePut, ve @CacheEvict anotasyonlarını ekleyebilirsiniz. Aşağıda örnek bir kullanım gösterilmektedir:


  13.    import org.springframework.cache.annotation.Cacheable;
  14.    import org.springframework.stereotype.Service;
  15.    
  16.    @Service
  17.    public class BookService {
  18.    
  19.        @Cacheable(value = "books", key = "#id")
  20.        public Book getBookById(String id) {
  21.            // Veritabanından kitabı getirme işlemi
  22.            System.out.println("Kitap veritabanından getiriliyor: " + id);
  23.            return new Book(id, "GraphQL with Spring", "John Doe");
  24.        }
  25.    }


    • @Cacheable: Metodun sonucunu önbelleğe alır. Eğer aynı parametrelerle metod tekrar çağrılırsa, sonuç doğrudan önbellekten alınır.
    • value: Redis'teki önbellek adı (örneğin, "books").
    • key: Önbellek anahtarı (örneğin, kitabın id değeri).


  1. Önbelleği Test Edin:
  2. Servis metotlarına eklediğiniz @Cacheable anotasyonuyla verilerin önbelleğe alınıp alınmadığını test edebilirsiniz. Örneğin, aynı id ile iki kez getBookById metodunu çağırdığınızda, ilk çağrı veritabanından gelir, ancak ikinci çağrı Redis'teki önbellekten gelir.

  3. Örnek çıktı:

  4.    Kitap veritabanından getiriliyor: 1


  5. İlk çağrıda bu mesajı göreceksiniz, ancak ikinci çağrıda bu mesaj çıkmaz, çünkü sonuç önbellekten alınır.

  6. @CacheEvict ile Önbellek Temizleme:
  7. Eğer önbelleğe alınmış bir değeri temizlemek istiyorsanız, @CacheEvict anotasyonunu kullanabilirsiniz:


  8.    @CacheEvict(value = "books", key = "#id")
  9.    public void deleteBook(String id) {
  10.        // Veritabanından kitabı silme işlemi
  11.    }


  12. Bu anotasyon, belirli bir id için önbellekteki veriyi siler.


Özet


  • Redis, Spring Boot projelerinde yüksek performanslı önbellekleme sağlamak için kullanılabilir.
  • Spring Boot ile Redis entegrasyonu, uygulamanızdaki veri erişim hızını artırabilir ve veritabanı yükünü azaltabilir.
  • @Cacheable, @CachePut, ve @CacheEvict anotasyonları ile Redis cache yönetimi kolayca yapılabilir.

  

Bu yapı, performans artışı sağlamanın yanı sıra, veritabanı sorgularını optimize etmek ve uygulamanızın ölçeklenebilirliğini artırmak için oldukça kullanışlıdır.

63. Zookeeper ile Konfigürasyon Yönetimi

  • Apache Zookeeper kullanarak mikroservisler arasında merkezi bir konfigürasyon yönetimi sağlayın.


64. Güvenli API'ler İçin CORS (Cross-Origin Resource Sharing) Yönetimi

  • Spring Security ile CORS ayarlarını yöneterek güvenli API'ler oluşturun:

  •   @Configuration
  •   public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  •       @Override
  •       protected void configure(HttpSecurity http) throws Exception {
  •           http.cors().and().csrf().disable();
  •       }
  •   
  •       @Bean
  •       public CorsConfigurationSource corsConfigurationSource() {
  •           CorsConfiguration configuration = new CorsConfiguration();
  •           configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
  •           configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
  •           UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  •           source.registerCorsConfiguration("/**", configuration);
  •           return source;
  •       }
  •   }


65. Asenkron REST Çağrıları

  • CompletableFuture ile asenkron REST çağrıları yapın:

  •   @Async
  •   public CompletableFuture<String> asyncMethod() {
  •       return CompletableFuture.completedFuture("Asynchronous response");
  •   }


66. File Upload (Dosya Yükleme)

  • MultipartFile kullanarak dosya yükleme işlemleri yapın:

  •   @PostMapping("/upload")
  •   public String uploadFile(@RequestParam("file") MultipartFile file) {
  •       if (!file.isEmpty()) {
  •           // Dosya yükleme işlemleri
  •       }
  •       return "File uploaded";
  •   }


67. Hazelcast ile Dağıtık Cache Kullanımı

  • Hazelcast ile dağıtık cache çözümü entegre edin:

  •   <dependency>
  •       <groupId>com.hazelcast</groupId>
  •       <artifactId>hazelcast-spring</artifactId>
  •   </dependency>


68. ElasticSearch Entegrasyonu

  • Spring Data Elasticsearch kullanarak verilerinizi Elasticsearch'e kaydedin ve arayın:

  •   <dependency>
  •       <groupId>org.springframework.boot</groupId>
  •       <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  •   </dependency>


69. Spring Cloud Gateway

  • Spring Cloud Gateway kullanarak mikroservisler arasında bir API geçidi sağlayın:

  •   <dependency>
  •       <groupId>org.springframework.cloud</groupId>
  •       <artifactId>spring-cloud-starter-gateway</artifactId>
  •   </dependency>


70. Spring Cloud Circuit Breaker

  • Resilience4j kullanarak Spring Cloud Circuit Breaker uygulaması oluşturun:

  •   <dependency>
  •       <groupId>org.springframework.cloud</groupId>
  •       <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
  •   </dependency>


71. Grafana ve Prometheus ile Metrik İzleme

  • Grafana ve Prometheus kullanarak Spring Boot uygulamanızın performansını izleyin ve metrikleri görüntüleyin.

71. Grafana ve Prometheus ile Metrik İzleme


Spring Boot uygulamalarınızda performansı ve sistem metriklerini izlemek için Grafana ve Prometheus entegrasyonu kullanabilirsiniz. Prometheus, metrikleri toplamak ve saklamak için kullanılan bir açık kaynak zaman serisi veri tabanı ve izleme sistemidir. Grafana ise bu metrikleri görselleştirmek ve izlemek için kullanılan güçlü bir grafik aracıdır. Bu iki araç bir arada kullanılarak Spring Boot uygulamalarınızın performansını, kaynak kullanımını ve diğer önemli metrikleri izleyebilirsiniz.


Aşağıda Spring Boot uygulamanıza Prometheus ve Grafana entegrasyonu ile nasıl metrik izleme ekleyebileceğinizi adım adım anlatıyorum.


1. Prometheus ve Grafana Nedir?


  • Prometheus: Zaman serisi veri toplama ve saklama sistemidir. Prometheus, uygulamalardan metrikleri toplar ve bu verileri sorgulayarak raporlar oluşturabilir.
  • Grafana: İzleme, analiz ve görselleştirme için kullanılan bir grafik platformudur. Prometheus'tan aldığı verileri görselleştirir ve kullanıcıya dashboard'lar sunar.


2. Spring Boot'ta Prometheus ve Grafana Entegrasyonu


Spring Boot uygulamanızı Prometheus ve Grafana ile izlemek için, Spring Boot uygulamanıza Micrometer ve Actuator desteğini eklemeniz gerekmektedir. Micrometer, Prometheus gibi izleme sistemlerine metrikleri toplamak için kullanılan bir kütüphanedir.


Adım 1: Gerekli Bağımlılıkları Ekleyin


Prometheus ve Micrometer entegrasyonu için micrometer-registry-prometheus ve spring-boot-starter-actuator bağımlılıklarını projenize ekleyin.


pom.xml



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>


<dependency>

    <groupId>io.micrometer</groupId>

    <artifactId>micrometer-registry-prometheus</artifactId>

</dependency>



Adım 2: Spring Actuator ve Prometheus Yapılandırması


Spring Boot Actuator, uygulama metriklerini toplamak ve Prometheus'a sunmak için kullanılır. application.properties dosyasına Prometheus ve Actuator ile ilgili gerekli yapılandırmayı ekleyin.


application.properties



# Actuator endpoint'lerini açalım

management.endpoints.web.exposure.include=health,info,prometheus


# Prometheus endpoint'i için ayarlar

management.metrics.export.prometheus.enabled=true

management.endpoint.prometheus.enabled=true



Bu yapılandırma, Actuator'ın prometheus endpoint'ini etkinleştirir ve metriklerin Prometheus formatında sunulmasını sağlar.


3. Prometheus Kurulumu ve Yapılandırması


Prometheus'u kurarak Spring Boot uygulamanızdan metrikleri toplamak için Prometheus yapılandırmasını yapmamız gerekiyor.


Adım 1: Prometheus Kurulumu


Prometheus'u Prometheus'un resmi sitesinden indirebilir ve yerel ortamınıza kurabilirsiniz. Ayrıca, Docker kullanarak Prometheus'u hızlıca çalıştırabilirsiniz.



docker run -d --name=prometheus -p 9090:9090 prom/prometheus



Adım 2: Prometheus Yapılandırması


Prometheus, uygulamalardan veri toplamak için bir yapılandırma dosyasına ihtiyaç duyar. Bu dosyada, Spring Boot uygulamanızın metriklerini toplamak için scrape ayarını yapın.


prometheus.yml



global:

  scrape_interval: 15s  # Her 15 saniyede bir metrik toplanacak


scrape_configs:

  - job_name: 'spring-boot-app'

    metrics_path: '/actuator/prometheus'

    static_configs:

      - targets: ['host.docker.internal:8080']



  • job_name: Prometheus'un hangi işten veri toplayacağını belirtir.
  • metrics_path: Metriklerin toplandığı Spring Boot Actuator endpoint'idir. Genelde /actuator/prometheus olur.
  • targets: Spring Boot uygulamasının çalıştığı sunucu adresi ve portu.


Yukarıdaki yapılandırmayı tamamladıktan sonra, Prometheus sunucusunu başlatın:



prometheus --config.file=prometheus.yml



Adım 3: Prometheus'u Test Etme


Prometheus'un doğru bir şekilde çalışıp çalışmadığını test etmek için Prometheus arayüzüne gidin. Tarayıcınıza http://localhost:9090 adresini girin ve Prometheus arayüzüne erişin. Daha sonra Targets sekmesine giderek, Spring Boot uygulamanızın Prometheus tarafından izlenip izlenmediğini kontrol edin.


4. Grafana ile Metriklerin Görselleştirilmesi


Grafana, Prometheus'tan aldığı verileri görselleştirmek için kullanılır. Grafana ile metriklerinizi izleyebilir ve performans analizi yapabilirsiniz.


Adım 1: Grafana Kurulumu


Grafana'yı resmi sitesinden indirerek kurabilirsiniz ya da Docker kullanarak hızlıca başlatabilirsiniz:



docker run -d --name=grafana -p 3000:3000 grafana/grafana



Grafana'yı çalıştırdıktan sonra, http://localhost:3000 adresine gidin. Varsayılan kullanıcı adı ve şifre admin/admin'dir.


Adım 2: Prometheus'u Veri Kaynağı Olarak Ekleme


Grafana arayüzüne giriş yaptıktan sonra, Prometheus'u veri kaynağı olarak ekleyin:


  1. Grafana paneline giriş yapın.
  2. Sol menüdeki Configuration (Yapılandırma) > Data Sources (Veri Kaynakları) sekmesine gidin.
  3. Add Data Source (Veri Kaynağı Ekle) butonuna tıklayın.
  4. Listeden Prometheus'u seçin.
  5. Prometheus URL kısmına http://localhost:9090 yazın ve Save & Test butonuna tıklayarak veri kaynağını ekleyin.


Adım 3: Dashboard (Panel) Oluşturma


Veri kaynağını ekledikten sonra, Grafana üzerinden bir dashboard oluşturarak metriklerinizi görselleştirebilirsiniz:


  1. Create (Oluştur) > Dashboard (Panel) sekmesine gidin.
  2. Add New Panel butonuna tıklayın.
  3. Prometheus'tan metrikleri sorgulamak için Metrics kısmına aşağıdaki gibi bir sorgu yazın:

  4.    http_server_requests_seconds_count

  5. Grafana, bu sorgu ile Spring Boot uygulamanızdaki HTTP istekleri hakkında bilgi alacak ve görselleştirecektir.


5. Spring Boot Uygulaması için Yaygın Metrikler


Spring Boot Actuator ve Micrometer, aşağıdaki gibi birçok metrik toplar:


  • http_server_requests_seconds_count: HTTP isteklerinin sayısı.
  • jvm_memory_used_bytes: JVM tarafından kullanılan bellek miktarı.
  • jvm_gc_pause_seconds: JVM Garbage Collection duraklamalarının süresi.
  • system_cpu_usage: CPU kullanım oranı.
  • process_uptime_seconds: Uygulamanın çalışma süresi.


Bu metrikleri Prometheus'ta sorgulayabilir ve Grafana'da görselleştirebilirsiniz.


6. Alerting (Alarm) Kurma


Grafana, kritik metrikler için uyarılar oluşturmanıza da olanak tanır. Örneğin, CPU kullanımı belirli bir değeri aştığında veya bellek kullanımı çok yüksek olduğunda Grafana ile bir alarm oluşturabilirsiniz. Bu, sistem yöneticilerine uyarı göndermek için çok kullanışlıdır.


Adım 1: Alarm Oluşturma


  1. Dashboard (Panel) üzerinde bir grafik paneli seçin.
  2. Edit (Düzenle) > Alert sekmesine gidin.
  3. Bir koşul belirleyin (örneğin, CPU kullanım oranı %80'in üzerine çıktığında).
  4. Alarm tetiklendiğinde e-posta veya Slack gibi entegrasyonlarla bildirim alınmasını sağlayın.


7. Docker Compose ile Prometheus ve Grafana Entegrasyonu


Aşağıda, Spring Boot uygulamanızı Docker Compose kullanarak Prometheus ve Grafana ile entegre eden bir örnek verilmiştir:



version: '3'

services:

  spring-boot-app:

    image: your-spring-boot-app-image

    ports:

      - "8080:8080"

  

  prometheus:

    image: prom/prometheus

    ports:

      - "9090:9090"

    volumes:

      - ./prometheus.yml:/etc/prometheus/prometheus.yml


  graf


ana:

    image: grafana/grafana

    ports:

      - "3000:3000"



Bu yapılandırma, Docker kullanarak Spring Boot uygulamanız ile Prometheus ve Grafana’yı aynı ortamda çalıştırır.


Özet:


  • Prometheus metrikleri toplamak için kullanılırken, Grafana bu metrikleri görselleştirmek için kullanılır.
  • Spring Boot, Actuator ve Micrometer kullanarak Prometheus'a metrik sağlar.
  • Grafana ile uygulamanızın performansını izleyebilir, görsel paneller oluşturabilir ve alarmlar kurabilirsiniz.


Bu yapılar sayesinde uygulamalarınızın performansını detaylı bir şekilde izleyebilir ve gerektiğinde anlık aksiyonlar alabilirsiniz.

72. Spring Boot AOP (Aspect-Oriented Programming)

  • AspectJ kullanarak AOP işlemleri yapın:

  •   @Aspect
  •   @Component
  •   public class LoggingAspect {
  •       @Before("execution(* com.example.*.*(..))")
  •       public void logBefore(JoinPoint joinPoint) {
  •           System.out.println("Method executed: " + joinPoint.getSignature());
  •       }
  •   }

Aspect-Oriented Programming (AOP), yazılım geliştirmede çapraz kesen endişeleri (cross-cutting concerns) yönetmek için kullanılan bir programlama paradigmadır. Spring AOP, bu paradigmaya dayalı olarak çalışan bir mekanizmadır ve programın temel mantığını etkilemeden loglama, güvenlik, işlem yönetimi gibi işlevleri merkezi bir şekilde yönetmenizi sağlar. Spring Boot, AspectJ ile birlikte AOP işlemlerini destekler.


1. AOP Nedir?


AOP, uygulamanın temel iş mantığını değiştirmeden, belirli kesişim noktalarında (örneğin, bir method çağrılmadan önce veya sonra) belirli davranışlar eklemenize olanak tanır. Bu yaklaşım, tekrar eden görevleri (örneğin, loglama, hata yönetimi, yetkilendirme) merkezi bir yerde tanımlamanızı ve yönetmenizi sağlar.


AOP’nin temel bileşenleri şunlardır:

  • Aspect: Kesişen davranışların tanımlandığı modüldür. Örneğin, bir loglama işlemi bir "aspect" olabilir.
  • Advice: Aspect'in bir methoddan önce, sonra veya bir hata olduğunda ne yapacağını tanımlayan koddur.
  • Pointcut: Bir advice’in hangi method(lar)da çalışacağını tanımlar.
  • JoinPoint: Uygulama akışında bir advice’in bağlanabileceği bir kesişim noktasıdır (örn. method çağrıları).
  • Weaving: Aspect'lerin temel iş mantığına bağlanma işlemidir.


2. Spring Boot’ta AOP Yapılandırması


Spring Boot’ta AOP işlemleri yapmak için AspectJ'yi kullanarak loglama gibi çapraz kesen işlemleri merkezi olarak yönetebilirsiniz.


Adım 1: AOP Bağımlılıklarını Ekleyin


Spring Boot’ta AOP desteğini kullanabilmek için projenize gerekli bağımlılıkları ekleyin.


Maven:



<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-aop</artifactId>

</dependency>



Gradle:



implementation 'org.springframework.boot:spring-boot-starter-aop'



Bu bağımlılıklar, Spring Boot’un AOP desteğini etkinleştirir ve AspectJ ile birlikte kullanmanıza olanak tanır.


Adım 2: Aspect Sınıfı Yazma


Aspect sınıfı, loglama, yetkilendirme gibi çapraz kesen endişeleri yöneteceğiniz yerdir. Aşağıdaki örnekte bir loglama aspect’i oluşturulmuştur.



import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.springframework.stereotype.Component;


@Aspect

@Component

public class LoggingAspect {


    @Before("execution(* com.example.*.*(..))")

    public void logBefore(JoinPoint joinPoint) {

        System.out.println("Method executed: " + joinPoint.getSignature().getName());

    }

}



  • @Aspect: Bu sınıfın bir Aspect sınıfı olduğunu belirtir.
  • @Before: Bu, hedeflenen method çağrılmadan hemen önce çalışacak bir advice tanımlar.
  • execution(* com.example.*.*(..)): Tüm com.example paketi altındaki tüm sınıflardaki tüm methodları hedefler.


Bu örnekte, bir method çalıştırılmadan önce method adı konsola yazdırılacaktır.


Adım 3: Spring Boot Uygulamasında AOP’yi Kullanın


Loglama işleminin uygulamanızda nasıl çalıştığını görmek için örnek bir servis yazabilirsiniz.



import org.springframework.stereotype.Service;


@Service

public class MyService {


    public void performAction() {

        System.out.println("Action is being performed");

    }

}



Daha sonra bu servisi çağıran bir kontrolcü ekleyin:



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class MyController {


    @Autowired

    private MyService myService;


    @GetMapping("/perform")

    public String performAction() {

        myService.performAction();

        return "Action Performed";

    }

}



Bu örnekte, /perform endpoint’i çağrıldığında önce Aspect tarafından tanımlanan loglama işlemi çalışacak, ardından performAction methodu çalıştırılacaktır.


Adım 4: Uygulamayı Test Etme


Uygulamanızı başlattıktan sonra, bir tarayıcıdan veya curl komut satırı aracını kullanarak aşağıdaki URL'ye istek gönderebilirsiniz:



curl http://localhost:8080/perform



Beklenen çıktı şu şekilde olacaktır:



Method executed: performAction

Action is being performed



Burada, performAction methodu çalıştırılmadan önce logBefore methodu devreye girerek method adını konsola yazdırır.


3. Farklı Pointcut Tanımlamaları


Spring AOP'de daha spesifik pointcut'lar tanımlayarak hangi methodlara veya hangi durumlarda aspect’in devreye gireceğini kontrol edebilirsiniz. İşte bazı örnekler:


  • Belirli bir sınıftaki methodları hedeflemek:

  •   @Before("execution(* com.example.MyService.*(..))")
  •   public void logBefore(JoinPoint joinPoint) {
  •       System.out.println("Method executed: " + joinPoint.getSignature().getName());
  •   }


  • Belirli parametreye sahip methodları hedeflemek:

  •   @Before("execution(* com.example.*.*(String))")
  •   public void logBeforeStringMethods(JoinPoint joinPoint) {
  •       System.out.println("Method with String parameter executed: " + joinPoint.getSignature().getName());
  •   }


  • Belirli bir anotasyon ile işaretlenmiş methodları hedeflemek:

  •   @Before("@annotation(org.springframework.web.bind.annotation.GetMapping)")
  •   public void logBeforeGetMapping(JoinPoint joinPoint) {
  •       System.out.println("Method with @GetMapping executed: " + joinPoint.getSignature().getName());
  •   }


4. AOP Advice Türleri


AOP’de farklı durumlarda çalışacak advice’ler tanımlayabilirsiniz:

  • @Before: Method çağrılmadan hemen önce çalışır.
  • @After: Method tamamlandıktan sonra çalışır.
  • @AfterReturning: Method başarıyla tamamlandıktan sonra çalışır.
  • @AfterThrowing: Method bir hata fırlattığında çalışır.
  • @Around: Method çalışmadan önce ve sonra kontrol sağlar. Hem öncesinde hem sonrasında işlem yapmak için kullanılır.


Örnek @Around kullanımı:



import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;


@Aspect

@Component

public class TimingAspect {


    @Around("execution(* com.example.*.*(..))")

    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

        long start = System.currentTimeMillis();

        Object proceed = joinPoint.proceed();

        long executionTime = System.currentTimeMillis() - start;

        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");

        return proceed;

    }

}



Bu advice, bir methodun ne kadar sürede çalıştığını ölçüp konsola yazdırır.


Sonuç


Spring Boot uygulamalarında AOP, tekrar eden işlemleri merkezi bir şekilde yönetmenizi sağlar. AspectJ ile birlikte loglama, yetkilendirme, hata yönetimi gibi işlemleri methodların içerisine eklemek yerine, bu işlemleri çapraz kesen bir yapıda yönetebilirsiniz. Bu, uygulamanızın temiz ve sürdürülebilir bir mimariyle gelişmesine olanak tanır.

73. Request Parametre Doğrulama

  • @Valid ve @Validated anotasyonları ile API isteklerindeki parametrelerin doğruluğunu kontrol edin:

  •   @PostMapping("/users")
  •   public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
  •       // Kullanıcı oluşturma
  •   }

73. Request Parametre Doğrulama

Spring Boot uygulamalarında, API isteklerindeki parametrelerin doğruluğunu kontrol etmek ve gerekli doğrulama işlemlerini yapmak için @Valid ve @Validated anotasyonları kullanılır. Bu anotasyonlar, istek parametrelerinde belirlediğiniz kurallara uymayan verileri filtreleyip, hataları otomatik olarak yakalar ve kullanıcıya uygun hata mesajları döner.


Özet


  • @Valid ve @Validated anotasyonları, Spring Boot'ta API isteklerindeki parametrelerin doğruluğunu kontrol etmek için kullanılır.
  • @NotBlank, @Email, @Size gibi doğrulama anotasyonları ile parametrelerin geçerli olup olmadığı denetlenir.
  • Özel hata mesajları ve grup bazlı doğrulama gibi gelişmiş özelliklerle API doğrulamalarını özelleştirebilirsiniz.


Bu doğrulama işlemleri, API'nizin güvenliğini artırarak, hatalı veya eksik verilerin sisteme girmesini engeller.

74. Async Loglama

  • Uygulamanızda asenkron loglama sağlayarak performansı artırın:

  •   <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
  •       <appender-ref ref="FILE" />
  •   </appender>


75. Microservices Service Registry (Eureka)

  • Eureka Server kullanarak mikroservisler arasında merkezi bir servis kayıt ve keşif sistemi sağlayın:

  •   <dependency>
  •       <groupId>org.springframework.cloud</groupId>
  •       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  •   </dependency>

Microservices Service Registry (Eureka)


Netflix Eureka, mikroservis mimarilerinde hizmet kayıt ve keşif mekanizması sağlayan popüler bir servis keşfi aracıdır. Eureka Server, mikroservislerin kendilerini kaydettikleri ve diğer mikroservislerin bu hizmetleri dinamik olarak keşfettiği bir merkezi kayıt sistemi görevi görür. Bu mekanizma, mikroservislerin IP adresleri ve port numaralarını manuel olarak yönetmek zorunda kalmadan birbirleriyle iletişim kurmasını sağlar.


Eureka Kullanımı


Eureka kullanarak merkezi bir Service Registry ve Service Discovery çözümü kurmak için iki ana bileşen vardır:

  1. Eureka Server: Merkezi servis kayıt noktası.
  2. Eureka Client: Kendini Eureka Server'a kaydeden ve diğer servisleri keşfeden mikroservisler.


Aşağıda adım adım Eureka Server ve Client yapılandırması açıklanmıştır:


————————


1. Eureka Server Kurulumu


İlk olarak, Eureka Server'ı kurmak ve başlatmak gereklidir.


Adım 1: Bağımlılıkları Ekleyin


Spring Boot projenize Eureka Server için gerekli bağımlılıkları ekleyin. pom.xml dosyanıza şu bağımlılığı ekleyin:



<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>

</dependency>



Gradle kullanıyorsanız:



implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'



Adım 2: Eureka Server Konfigürasyonu


Ana sınıfınıza (main class) @EnableEurekaServer anotasyonunu ekleyin. Bu sınıf, uygulamanın Eureka Server olarak çalışmasını sağlayacaktır.



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;


@SpringBootApplication

@EnableEurekaServer

public class EurekaServerApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaServerApplication.class, args);

    }

}



Adım 3: application.properties Konfigürasyonu


application.properties dosyasına aşağıdaki konfigürasyonu ekleyin:



spring.application.name=eureka-server

server.port=8761


eureka.client.register-with-eureka=false

eureka.client.fetch-registry=false



Bu yapılandırma ile:

  • server.port=8761 ile Eureka Server uygulamanız 8761 portunda çalışır.
  • eureka.client.register-with-eureka=false ve fetch-registry=false parametreleri, Eureka Server’ın kendisini kaydetmeye çalışmamasını sağlar.


Adım 4: Eureka Server'ı Başlatın


Uygulamanızı başlattıktan sonra, tarayıcınızdan http://localhost:8761/ adresine giderek Eureka Server arayüzünü görebilirsiniz.


————————


2. Eureka Client (Mikroservis) Kurulumu


Eureka Client, servislerin kendilerini Eureka Server'a kaydetmesi ve diğer servisleri keşfetmesini sağlar.


Adım 1: Bağımlılıkları Ekleyin


Her bir mikroservis için pom.xml dosyasına Eureka Client bağımlılığını ekleyin:



<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

</dependency>



Gradle için:



implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'



Adım 2: @EnableEurekaClient Anotasyonunu Ekleyin


Mikroservislerin ana sınıfına (main class) @EnableEurekaClient anotasyonunu ekleyin:



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;


@SpringBootApplication

@EnableEurekaClient

public class MyServiceApplication {

    public static void main(String[] args) {

        SpringApplication.run(MyServiceApplication.class, args);

    }

}



Adım 3: application.properties Konfigürasyonu


Her mikroservis için application.properties dosyasına Eureka Server'a kaydolmak için gerekli ayarları ekleyin:



spring.application.name=my-service

server.port=8081


eureka.client.service-url.defaultZone=http://localhost:8761/eureka/



Bu konfigürasyonla:

  • spring.application.name=my-service ile mikroservisin adı tanımlanır.
  • eureka.client.service-url.defaultZone ile mikroservis Eureka Server'a hangi adreste kaydolacağını öğrenir.


Adım 4: Mikroservisi Başlatın


Bu adımları takip eden her mikroservis, Eureka Server’a kaydolur ve diğer servisleri keşfedebilir.


————————


3. Servis Keşfi (Service Discovery)


Bir mikroservis, Eureka Server'a kaydolan diğer servisleri dinamik olarak keşfedebilir. Spring Boot kullanarak bir servisi bulmak için RestTemplate veya WebClient kullanılabilir.


Örneğin, RestTemplate ile başka bir servise çağrı yapmak için:



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;


@RestController

public class MyController {


    @Autowired

    private RestTemplate restTemplate;


    @GetMapping("/call-service")

    public String callOtherService() {

        String serviceUrl = "http://my-other-service/hello";

        return restTemplate.getForObject(serviceUrl, String.class);

    }

}



Bu örnekte http://my-other-service/hello ile bir başka mikroservise çağrı yapılır. Eureka, my-other-service adındaki servisin IP adresini ve portunu dinamik olarak çözecektir.


RestTemplate Bean Tanımı


RestTemplate, mikroservislerin birbirini keşfetmesi için load balancer kullanılarak yapılandırılmalıdır:



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.client.RestTemplate;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;


@Configuration

public class Config {


    @Bean

    @LoadBalanced

    public RestTemplate restTemplate() {

        return new RestTemplate();

    }

}



————————


4. Eureka ile Yük Dengeleme (Load Balancing)


Eureka Client, aynı isimde birden fazla mikroservisin kaydedilmesi durumunda, bu mikroservisler arasında yük dengeleme işlemi yapabilir. Bu sayede mikroservisler arasında otomatik yük dengeleme ve hata toleransı sağlanır.


————————


Sonuç


Netflix Eureka, mikroservis mimarilerinde merkezi bir Service Registry ve Service Discovery çözümü sunar. Mikroservisler Eureka Server'a kaydolur ve diğer servisleri dinamik olarak keşfeder. Bu sayede dağıtık sistemlerde servislerin birbirini manuel olarak yönetmesine gerek kalmadan, yük dengeleme, hata toleransı ve merkezi servis yönetimi sağlanmış olur.

76. Spring Boot Docker Entegrasyonu

  • Dockerfile oluşturarak uygulamanızı containerize edin:

  •   FROM openjdk:11
  •   ADD target/demo.jar demo.jar
  •   ENTRYPOINT ["java", "-jar", "demo.jar"]


77. SonarQube ile Kod Kalitesi Analizi

  • SonarQube kullanarak Spring Boot uygulamanızın kod kalitesini analiz edin ve iyileştirin.


78. Testcontainers ile Entegre Testler

  • Testcontainers kullanarak veri tabanı gibi dış bağımlılıklarla entegre testler gerçekleştirin:

  •   <dependency>
  •       <groupId>org.testcontainers</groupId>
  •       <artifactId>mysql</artifactId>
  •       <scope>test</scope>
  •   </dependency>


79. Thymeleaf ile HTML Şablonları

  • Thymeleaf kullanarak dinamik HTML sayfaları oluşturun:

  •   <dependency>
  •       <groupId>org.springframework.boot</groupId>
  •       <artifactId>spring-boot-starter-thymeleaf</artifactId>
  •   </dependency>


80. API Rate Limiting (Trafik Kontrolü)

  • Bucket4j veya Spring Cloud Gateway kullanarak API isteklerini sınırlayın:

  •   <dependency>
  •       <groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
  •       <artifactId>bucket4j-spring-boot-starter</artifactId>
  •   </dependency>


  • Bir rate limiting kuralı oluşturun:

  •   @Bean
  •   public FilterRegistrationBean<RateLimitFilter> rateLimitFilter() {
  •       FilterRegistrationBean<RateLimitFilter> registrationBean = new FilterRegistrationBean<>();
  •       registrationBean.setFilter(new RateLimitFilter());
  •       return registrationBean;
  •   }


81. Reactive Programming - Spring WebFlux

  • Spring WebFlux ile reaktif programlama paradigmasını kullanarak yüksek performanslı, asenkron uygulamalar geliştirin:

  •   @RestController
  •   @RequestMapping("/reactive")
  •   public class ReactiveController {
  •       @GetMapping("/flux")
  •       public Flux<String> getFlux() {
  •           return Flux.just("Spring", "WebFlux", "Reactive");
  •       }
  •   }


82. Spring Boot ile SSE (Server-Sent Events)

  • Sunucudan istemciye gerçek zamanlı veri akışı sağlamak için SSE kullanın:

  •   @GetMapping(value = "/stream-sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  •   public Flux<String> streamEvents() {
  •       return Flux.interval(Duration.ofSeconds(1)).map(seq -> "Event " + seq);
  •   }


83. Spring Boot ile Kubernetes Entegrasyonu

  • Spring Boot uygulamanızı Kubernetes üzerinde çalıştırın ve dağıtım yapın. Kubernetes konfigürasyonu için Deployment ve Service dosyaları oluşturun:

  •   apiVersion: apps/v1
  •   kind: Deployment
  •   metadata:
  •     name: spring-boot-app
  •   spec:
  •     replicas: 2
  •     selector:
  •       matchLabels:
  •         app: spring-boot-app
  •     template:
  •       metadata:
  •         labels:
  •           app: spring-boot-app
  •       spec:
  •         containers:
  •         - name: spring-boot-app
  •           image: your-docker-image
  •           ports:
  •           - containerPort: 8080


84. OpenAPI (Swagger) ile API Dokümantasyonu

  • OpenAPI ve Swagger kullanarak REST API'lerinizi otomatik olarak dokümante edin:

  •   <dependency>
  •       <groupId>org.springdoc</groupId>
  •       <artifactId>springdoc-openapi-ui</artifactId>
  •       <version>1.5.9</version>
  •   </dependency>


85. Spring Boot ile SOAP Web Servisleri

  • SOAP kullanarak Spring Boot üzerinde web servisleri geliştirin:

  •   <dependency>
  •       <groupId>org.springframework.boot</groupId>
  •       <artifactId>spring-boot-starter-web-services</artifactId>
  •   </dependency>


  • SOAP web servisini tanımlayın:

  •   @Endpoint
  •   public class CountryEndpoint {
  •       @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
  •       @ResponsePayload
  •       public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
  •           GetCountryResponse response = new GetCountryResponse();
  •           response.setCountry(countryRepository.findCountry(request.getName()));
  •           return response;
  •       }
  •   }


86. Consul ile Servis Keşfi ve Konfigürasyon Yönetimi

  • Consul kullanarak servis keşfi ve merkezi konfigürasyon yönetimi sağlayın.


87. Prometheus ve Micrometer ile Metrik Toplama

  • Micrometer ile uygulamanızın metriklerini toplayın ve Prometheus ile izleyin:

  •   <dependency>
  •       <groupId>io.micrometer</groupId>
  •       <artifactId>micrometer-registry-prometheus</artifactId>
  •   </dependency>


88. Distributed Tracing (Dağıtık İzleme)

  • Spring Cloud Sleuth ve Zipkin kullanarak mikroservisler arasında dağıtık izleme sağlayın:

  •   <dependency>
  •       <groupId>org.springframework.cloud</groupId>
  •       <artifactId>spring-cloud-starter-sleuth</artifactId>
  •   </dependency>


89. Spring Boot ile HTTP/2 Desteği

  • Spring Boot uygulamanızda HTTP/2 desteği sağlayarak daha hızlı ve performanslı bağlantılar elde edin:

  •   server.http2.enabled=true


90. Spring Boot ile WebClient Kullanımı

  • RestTemplate yerine modern WebClient'i kullanarak asenkron HTTP istekleri gerçekleştirin:

  •   WebClient client = WebClient.create("http://localhost:8080");
  •   client.get()
  •         .uri("/products")
  •         .retrieve()
  •         .bodyToFlux(Product.class);


91. Spring Boot Native - GraalVM ile Native Image

  • GraalVM kullanarak Spring Boot uygulamanızı native bir binary haline getirin ve daha hızlı başlatma süreleri sağlayın:

  •   <dependency>
  •       <groupId>org.springframework.experimental</groupId>
  •       <artifactId>spring-native</artifactId>
  •   </dependency>


92. Zero Downtime Deployments (Sıfır Kesintiyle Dağıtım)

  • Kubernetes ve Spring Boot kullanarak sıfır kesinti ile uygulama dağıtımı gerçekleştirin, rolling updates yapılandırmasını kullanın.


93. Circuit Breaker ile Hata Yönetimi

  • Resilience4j kullanarak uygulamalarınızda devre kesici desenini uygulayın ve aşırı yüklemelerden korunun:

  •   @CircuitBreaker(name = "backendA", fallbackMethod = "fallbackMethod")
  •   public String process() {
  •       return restTemplate.getForObject("http://example.com", String.class);
  •   }


94. Liquibase ile Veri Tabanı Versiyonlama

  • Liquibase ile veri tabanı şema değişikliklerini yönetin:

  •   changeLog:
  •     - changeSet:
  •         id: 1
  •         author: yourname
  •         changes:
  •           - createTable:
  •               tableName: customer
  •               columns:
  •                 - column:
  •                     name: id
  •                     type: bigint
  •                     autoIncrement: true
  •                 - column:
  •                     name: name
  •                     type: varchar(255)


95. Spring Boot ile Distributed Locking (Dağıtık Kilitleme)

  • Redisson veya Zookeeper kullanarak dağıtık sistemlerde kilit mekanizmaları sağlayın:

  •   <dependency>
  •       <groupId>org.redisson</groupId>
  •       <artifactId>redisson-spring-boot-starter</artifactId>
  •   </dependency>


96. Reactive MongoDB Entegrasyonu

  • Spring Data Reactive MongoDB ile MongoDB’ye reaktif erişim sağlayın:

  •   public interface ProductRepository extends ReactiveMongoRepository<Product, String> {
  •   }


97. Fault Tolerance Patterns (Hata Tolerans Desenleri)

  • Retry, Rate Limiting, Timeout gibi desenleri uygulayarak uygulamanızı daha dayanıklı hale getirin:

  •   @Retry(name = "retryService", fallbackMethod = "fallbackMethod")
  •   public String process() {
  •       return restTemplate.getForObject("http://example.com", String.class);
  •   }


98. Spring Boot ve Apache Kafka Streams Entegrasyonu

  • Kafka Streams kullanarak veri akışlarını işleyin ve analiz edin:

  •   <dependency>
  •       <groupId>org.springframework.kafka</groupId>
  •       <artifactId>spring-kafka</artifactId>
  •   </dependency>


99. ETL (Extract, Transform, Load) İşlemleri

  • Spring Batch ile veri işleme, ETL operasyonları gerçekleştirin:

  •   <dependency>
  •       <groupId>org.springframework.boot</groupId>
  •       <artifactId>spring-boot-starter-batch</artifactId>
  •   </dependency>


  • Bir batch job oluşturun:

  •   @Bean
  •   public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
  •       return jobBuilderFactory.get("importUserJob")
  •               .incrementer(new RunIdIncrementer())
  •               .listener(listener)
  •               .flow(step1)
  •               .end()
  •               .build();
  •   }


100. API Gateway ile API Yönetimi

  • Spring Cloud API Gateway kullanarak mikroservislerinizi tek bir noktadan yönetip, proxy servisi sağlayın:

  •   spring:
  •     cloud:
  •       gateway:
  •         routes:
  •           - id: product-service
  •             uri: http://localhost:8081

              

Please Select Embedded Mode To Show The Comment System.*

Daha yeni Daha eski

نموذج الاتصال