Takip et

Spring Batch Örneği ile Büyük Veri İşlemleri Yönetimi

Spring Batch Örneği ile Büyük Veri İşlemleri Yönetimi Spring Batch, kurumsal düzeyde güçlü ve ölçeklenebilir batch uygulamaları gelişt

Spring Batch Örneği ile Büyük Veri İşlemleri Yönetimi

Spring Batch, kurumsal düzeyde güçlü ve ölçeklenebilir batch uygulamaları geliştirmek için tasarlanmış açık kaynaklı bir framework’tür. Genellikle belirli bir zamanda, çok sayıda veri kaydını içeren tekrarlayan görevleri otomatikleştirmek için kullanılır. Bu tür işlemler, finansal raporlama, büyük veri setlerinin migrasyonu, ETL (Extract, Transform, Load) süreçleri, faturalama ve periyodik veri temizleme gibi alanlarda kritik öneme sahiptir. Spring Batch, bu karmaşık görevleri yönetmek için sağlam bir yapı, hata yönetimi, yeniden başlatılabilirlik ve izlenebilirlik gibi temel özellikleri sunarak geliştiricilerin iş yükünü önemli ölçüde hafifletir.

Bu makalede, Spring Batch’in temel kavramlarını derinlemesine inceleyecek, pratik bir örnek üzerinden adım adım bir batch uygulamasının nasıl oluşturulduğunu gösterecek ve ardından framework’ün sunduğu gelişmiş özelliklere değineceğiz. Amacımız, Spring Batch’in büyük veri işlemlerini yönetme konusundaki gücünü ve esnekliğini anlamanızı sağlamaktır.

Spring Batch Temelleri

Büyük veri setleriyle çalışmak, genellikle çevrimiçi (online) işlemlere kıyasla farklı bir yaklaşım gerektirir. Çevrimiçi işlemler genellikle anlık, kullanıcı odaklı ve küçük veri parçacıkları üzerinde çalışırken, batch işlemleri arka planda, kullanıcı etkileşimi olmadan ve çok daha büyük veri hacimlerini işlemek üzere tasarlanmıştır.

Batch İşleme Nedir?

Batch işleme, belirli bir zamanda toplanan veya biriktirilen bir grup işlemi veya veriyi tek bir birim olarak işleme sürecidir. Bu işlemler genellikle insan müdahalesi olmadan çalışır ve kaynakların daha az yoğun olduğu zamanlarda (örneğin gece saatleri) çalıştırılır. Batch işlemlerinin temel özellikleri şunlardır:

* Tekrarlanabilirlik: Aynı girdi verisiyle tekrar çalıştırıldığında aynı sonucu üretmelidir.
* Otomasyon: Manuel müdahale olmadan çalışacak şekilde tasarlanmıştır.
* Büyük Veri Hacmi: Milyonlarca kaydı işleyebilme kapasitesi.
* Hata Toleransı: Bir hata durumunda işlemi durdurabilme, hatayı kaydedebilme ve belirli bir noktadan yeniden başlatabilme yeteneği.
* İzlenebilirlik: İşlemin durumu, ilerlemesi ve sonuçları hakkında bilgi sağlayabilme.

Kullanım alanlarına örnek olarak bankacılıkta gün sonu işlemleri, telekomünikasyonda faturalama, e-ticarette stok güncellemeleri veya rapor üretimi verilebilir.

Spring Batch Neden Kullanılmalı?

Spring Batch, batch uygulamalarının geliştirilmesinde karşılaşılan zorlukları ele almak için tasarlanmıştır. Geliştiricilere şu avantajları sunar:

* Robustluk ve Güvenilirlik: İşlemlerin hata durumunda dahi tutarlı kalmasını sağlar. Yeniden başlatılabilirlik özelliği sayesinde, kesintiye uğrayan bir işlem en son başarılı noktadan devam edebilir.
* Ölçeklenebilirlik: Büyük veri hacimlerini işlemek için çeşitli stratejiler (paralel adımlar, bölümlendirme, uzaktan yığınlama) sunar.
* Hata Yönetimi: Okuma, işleme ve yazma aşamalarında meydana gelen hataları yakalama, atlama (skip) veya tekrar deneme (retry) mekanizmaları sağlar.
* İzlenebilirlik ve Yönetim: Tüm batch işlemlerinin meta verilerini (başlangıç zamanı, bitiş zamanı, durumu, adım bilgileri vb.) bir veritabanında saklar. Bu sayede işlemlerin durumunu kolayca izlemek ve yönetmek mümkün olur.
* Basitleştirilmiş Geliştirme: Çoğu batch işleme senaryosunda tekrar eden (boilerplate) kodu ortadan kaldırır ve geliştiricilerin iş mantığına odaklanmasını sağlar. Spring ekosistemiyle tam entegrasyon sunar.

Temel Kavramlar

Spring Batch’in mimarisi, belirli bir dizi temel kavram üzerine kuruludur. Bu kavramları anlamak, etkili batch uygulamaları geliştirmek için hayati öneme sahiptir.

* Job (İş): Bir batch işleminin tamamını temsil eden ana birimdir. Bir Job, bir veya daha fazla Step‘ten oluşur. Örneğin, “Kullanıcı Verilerini Aktar” bir Job olabilir.
* Step (Adım): Bir Job içindeki tekil, bağımsız bir aşamadır. Her Step kendi başına bir görevi yerine getirir. Örneğin, “CSV Dosyasını Oku”, “Veriyi Temizle”, “Veritabanına Yaz” ayrı birer Step olabilir.
* JobInstance: Bir Job‘ın belirli bir çalıştırmasını temsil eder. Aynı Job‘ı farklı parametrelerle veya farklı zamanlarda çalıştırdığınızda, her biri ayrı bir JobInstance oluşturur.
* JobExecution: Bir JobInstance‘ın tek bir çalıştırma denemesidir. Bir JobInstance başarısız olursa ve yeniden başlatılırsa, yeni bir JobExecution oluşturulur.
* StepExecution: Bir Step‘in tek bir çalıştırma denemesidir. Her JobExecution içinde birden fazla StepExecution bulunur.
* ItemReader: Veriyi okuma sorumluluğunu üstlenen bileşendir. Çeşitli veri kaynaklarından (CSV, XML, veritabanı, JMS kuyruğu vb.) veri okuyabilir.
* ItemProcessor: Okunan veriyi işleme, dönüştürme veya doğrulama sorumluluğunu üstlenen isteğe bağlı bir bileşendir. ItemReader‘dan okunan nesneyi alır, işler ve ItemWriter‘a aktarılacak başka bir nesne döndürür.
* ItemWriter: İşlenen veriyi kalıcı bir depolama alanına (veritabanı, dosya, JMS kuyruğu vb.) yazma sorumluluğunu üstlenen bileşendir.
* Chunk-Oriented Processing (Yığın Odaklı İşleme): Spring Batch’in en yaygın Step türüdür. Bu modelde, ItemReader belirli bir sayıda (yığın boyutu – chunk size) öğeyi okur, ItemProcessor bu öğeleri işler ve ItemWriter işlenen tüm öğeleri tek bir işlem (transaction) içinde yazar. Bu yaklaşım, performans ve kaynak yönetimi açısından oldukça etkilidir.
* Tasklet: Basit, tek seferlik görevleri yerine getirmek için kullanılan bir Step türüdür. Örneğin, bir dosya silme, bir SQL komutu çalıştırma veya bir web servisi çağırma gibi görevler için idealdir. ItemReader, ItemProcessor, ItemWriter döngüsünü kullanmayan durumlarda tercih edilir.
* JobLauncher: Bir Job‘ı başlatmak için kullanılan bir arayüzdür. Genellikle JobParameters ile birlikte bir Job‘ı tetikler.
* JobRepository: Tüm batch işleminin meta verilerini (JobInstance, JobExecution, StepExecution, JobParameters vb.) kalıcı olarak saklayan anahtar bileşendir. Bu, yeniden başlatılabilirlik ve izlenebilirlik için gereklidir.
* JobExplorer: JobRepository‘de saklanan meta verilere salt okunur erişim sağlar.

Bir Spring Batch Örneği Oluşturma

Şimdi Spring Batch’in temel bileşenlerini kullanarak basit bir batch uygulamasını adım adım geliştirelim. Senaryomuz, bir CSV dosyasından kullanıcı verilerini okumak, bu verileri işlemek (örneğin e-posta adresini küçük harfe çevirmek) ve ardından bir veritabanına kaydetmektir.

Proje Kurulumu

Spring Boot ile yeni bir proje oluşturarak başlayacağız. Bunun için Spring Initializr (start.spring.io) kullanabiliriz.
Gerekli bağımlılıklar:

* Spring Batch: spring-boot-starter-batch
* Spring Data JPA: spring-boot-starter-data-jpa (veritabanına yazmak için)
* H2 Database: h2 (geliştirme ve örnek için in-memory veritabanı)



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        3.2.5
         
    
    com.example
    spring-batch-example
    0.0.1-SNAPSHOT
    spring-batch-example
    Spring Batch Example Project
    
        17
    
    
        
            org.springframework.boot
            spring-boot-starter-batch
        
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        
        
            com.h2database
            h2
            runtime
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.batch
            spring-batch-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

Veri Modeli Tanımlama

Kullanıcı verilerini temsil edecek bir JPA varlığı (entity) tanımlayalım.

package com.example.springbatchexample.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstName;
    private String lastName;
    private String email;
    private String status; // Örneğin, ACTIVE, INACTIVE

    // toString, equals, hashCode Lombok tarafından sağlanır.
}

Bu User varlığını kaydetmek için basit bir JPA deposu (repository) da oluşturalım:

package com.example.springbatchexample.repository;

import com.example.springbatchexample.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository {
}

Job Tanımlama ve Yapılandırma

Batch işlemini yapılandıran ana sınıfı oluşturalım. Bu sınıf, Job ve Step bean’lerini tanımlayacaktır.

package com.example.springbatchexample.config;

import com.example.springbatchexample.model.User;
import com.example.springbatchexample.processor.UserItemProcessor;
import com.example.springbatchexample.repository.UserRepository;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.data.RepositoryItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
public class BatchConfig {

    private final JobRepository jobRepository;
    private final PlatformTransactionManager transactionManager;
    private final UserRepository userRepository;

    public BatchConfig(JobRepository jobRepository, PlatformTransactionManager transactionManager, UserRepository userRepository) {
        this.jobRepository = jobRepository;
        this.transactionManager = transactionManager;
        this.userRepository = userRepository;
    }

    // ItemReader: CSV dosyasından veriyi okur
    @Bean
    public FlatFileItemReader reader() {
        FlatFileItemReader itemReader = new FlatFileItemReader<>();
        itemReader.setResource(new ClassPathResource("users.csv")); // resources klasöründeki dosya
        itemReader.setName("csvReader");
        itemReader.setLinesToSkip(1); // Başlık satırını atla
        itemReader.setLineMapper(lineMapper());
        return itemReader;
    }

    @Bean
    public LineMapper lineMapper() {
        DefaultLineMapper lineMapper = new DefaultLineMapper<>();

        DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
        lineTokenizer.setDelimiter(","); // CSV virgülle ayrılmış
        lineTokenizer.setStrict(false);
        lineTokenizer.setNames("firstName", "lastName", "email", "status"); // CSV'deki kolon adları

        BeanWrapperFieldSetMapper fieldSetMapper = new BeanWrapperFieldSetMapper<>();
        fieldSetMapper.setTargetType(User.class); // Hedef sınıfımız User

        lineMapper.setLineTokenizer(lineTokenizer);
        lineMapper.setFieldSetMapper(fieldSetMapper);
        return lineMapper;
    }

    // ItemProcessor: Okunan veriyi işler/dönüştürür
    @Bean
    public UserItemProcessor processor() {
        return new UserItemProcessor();
    }

    // ItemWriter: İşlenen veriyi veritabanına yazar
    @Bean
    public RepositoryItemWriter writer() {
        RepositoryItemWriter writer = new RepositoryItemWriter<>();
        writer.setRepository(userRepository);
        writer.setMethodName("save"); // UserRepository'deki save metodunu kullan
        return writer;
    }

    // Step: Okuma -> İşleme -> Yazma adımı
    @Bean
    public Step importStep() {
        return new StepBuilder("csvImportStep", jobRepository)
                .chunk(10, transactionManager) // Her 10 kayıtta bir commit et
                .reader(reader())
                .processor(processor())
                .writer(writer())
                .build();
    }

    // Job: Tüm batch işlemini tanımlar
    @Bean
    public Job importUserJob() {
        return new JobBuilder("importUserJob", jobRepository)
                .flow(importStep())
                .end()
                .build();
    }
}

Uygulama sınıfına @EnableBatchProcessing eklemeyi unutmayın:

package com.example.springbatchexample;

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableBatchProcessing // Spring Batch özelliklerini etkinleştirir
public class SpringBatchExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBatchExampleApplication.class, args);
    }
}

ItemReader Oluşturma

BatchConfig sınıfında reader() metodunu tanımladık. Bu metod, FlatFileItemReader kullanarak users.csv dosyasını okur.
* setResource(new ClassPathResource("users.csv")): src/main/resources altındaki users.csv dosyasını belirtir.
* setLinesToSkip(1): CSV dosyasının ilk satırının başlık olduğunu varsayarak bu satırı atlar.
* setLineMapper(lineMapper()): Her satırı User nesnesine nasıl eşleyeceğini belirten bir LineMapper kullanır.
* DefaultLineMapper: Satırı token’lara ayırmak için DelimitedLineTokenizer ve bu token’ları bir nesneye eşlemek için BeanWrapperFieldSetMapper kullanır.
* DelimitedLineTokenizer: Virgülle ayrılmış (delimiter) alanları ayırır ve firstName, lastName, email, status adlarını verir. Bu adlar User sınıfındaki alan adlarıyla eşleşmelidir.
* BeanWrapperFieldSetMapper: Token’ları User sınıfının ilgili alanlarına otomatik olarak eşler.

ItemProcessor Oluşturma

UserItemProcessor sınıfı, ItemProcessor arayüzünü implement eder ve okunan User nesnesi üzerinde bazı dönüşümler yapar. Örneğin, e-posta adresini küçük harfe çevirebiliriz.

package com.example.springbatchexample.processor;

import com.example.springbatchexample.model.User;
import org.springframework.batch.item.ItemProcessor;

public class UserItemProcessor implements ItemProcessor {

    @Override
    public User process(User user) throws Exception {
        // E-posta adresini küçük harfe çevir
        String processedEmail = user.getEmail().toLowerCase();
        user.setEmail(processedEmail);
        // İsimleri büyük harfe çevirme gibi başka işlemler de yapılabilir
        user.setFirstName(user.getFirstName().toUpperCase());
        user.setLastName(user.getLastName().toUpperCase());
        // Durumu kontrol etme veya varsayılan değer atama
        if (user.getStatus() == null || user.getStatus().isEmpty()) {
            user.setStatus("ACTIVE");
        }
        return user; // İşlenmiş User nesnesini döndür
    }
}

ItemWriter Oluşturma

writer() metodu, RepositoryItemWriter kullanarak işlenen User nesnelerini UserRepository aracılığıyla veritabanına kaydeder.
* setRepository(userRepository): Kullanılacak JPA deposunu belirtir.
* setMethodName("save"): UserRepository üzerindeki save metodunun çağrılacağını belirtir.

Job Çalıştırma ve Tetikleme

Batch işlemini başlatmak için bir CommandLineRunner kullanabiliriz. Bu, uygulamanın başladığında işi otomatik olarak tetikleyecektir.

package com.example.springbatchexample;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class JobRunner implements CommandLineRunner {

    private final JobLauncher jobLauncher;
    private final Job importUserJob;

    public JobRunner(JobLauncher jobLauncher, Job importUserJob) {
        this.jobLauncher = jobLauncher;
        this.importUserJob = importUserJob;
    }

    @Override
    public void run(String... args) throws Exception {
        // Her çalıştırmada benzersiz bir JobParameters sağlamak önemlidir.
        // Aksi takdirde, JobRepository aynı JobInstance'ı tekrar çalıştırmaya çalışır.
        JobParameters jobParameters = new JobParametersBuilder()
                .addLong("startAt", System.currentTimeMillis())
                .toJobParameters();

        try {
            jobLauncher.run(importUserJob, jobParameters);
            System.out.println("Batch Job finished successfully!");
        } catch (Exception e) {
            System.err.println("Batch Job failed: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

JobParameters önemi: Spring Batch, bir Job‘ın aynı JobParameters ile birden fazla kez çalıştırılmasını varsayılan olarak engeller. Bu, bir JobInstance‘ın benzersizliğini sağlar. Bu nedenle, her çalıştırmada benzersiz bir parametre (örneğin, System.currentTimeMillis()) eklemek önemlidir.

Uygulama Yapılandırması

src/main/resources/application.properties dosyasına H2 veritabanı ve Spring Batch için gerekli yapılandırmaları ekleyelim:

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update

Spring Batch meta verilerini H2 veritabanında sakla

spring.batch.jdbc.initialize-schema=always logging.level.org.springframework.batch=DEBUG

users.csv dosyası: src/main/resources klasörüne aşağıdaki gibi bir users.csv dosyası ekleyin:

firstName,lastName,email,status
John,Doe,john.doe@example.com,ACTIVE
Jane,Smith,jane.smith@example.com,ACTIVE
Peter,Jones,peter.jones@example.com,INACTIVE
Alice,Williams,alice.williams@example.com,ACTIVE

Bu adımları tamamladıktan sonra uygulamayı çalıştırdığınızda, Spring Batch otomatik olarak users.csv dosyasını okuyacak, verileri işleyecek ve H2 veritabanına kaydedecektir. H2 konsolunu (http://localhost:8080/h2-console) kullanarak verilerin başarıyla kaydedilip kaydedilmediğini kontrol edebilirsiniz.

Gelişmiş Spring Batch Özellikleri

Spring Batch sadece temel okuma-işleme-yazma döngüsünden ibaret değildir; aynı zamanda kurumsal düzeyde batch uygulamaları için birçok gelişmiş özellik sunar.

Hata Yönetimi ve Yeniden Başlatılabilirlik

Batch işlemlerinde hatalar kaçınılmazdır. Spring Batch, bu hataları zarif bir şekilde yönetmek ve işleri kesintiye uğradığında yeniden başlatmak için güçlü mekanizmalar sunar.

* skip ve skipLimit: ItemReader, ItemProcessor veya ItemWriter sırasında belirli türdeki hataları atlamayı ve işleme devam etmeyi sağlar. Örneğin, bir CSV dosyasındaki bozuk bir satırı atlayıp diğerlerini işlemeye devam edebilirsiniz. skipLimit, atlanabilecek maksimum hata sayısını belirler.
* noRollbackFor: Bir işlem sırasında belirli istisna türlerinin transaction’ı geri almasını engeller. Bu, belirli “iş” istisnalarını (örneğin, geçersiz bir kayıt) bir hata olarak işaretleyip işlemi devam ettirmek istediğinizde kullanışlıdır.
* retry ve retryLimit: Geçici hatalar (örneğin, veritabanı bağlantı kesintisi) durumunda bir işlemi otomatik olarak tekrar denemeyi sağlar.
* Yeniden Başlatılabilirlik: JobRepository‘nin sağladığı en önemli özelliklerden biridir. Bir JobExecution başarısız olduğunda veya manuel olarak durdurulduğunda, Spring Batch en son başarılı Step‘ten veya chunk‘tan işleme devam edebilir. Bu, uzun süren batch işlemlerinde zaman ve kaynak tasarrufu sağlar.

Performans ve Ölçeklenebilirlik

Büyük veri setleriyle çalışırken performans kritik öneme sahiptir. Spring Batch, farklı ölçeklenebilirlik stratejileri sunar:

* Chunk size optimizasyonu: chunk() metoduyla belirtilen yığın boyutu, performans üzerinde büyük etkiye sahiptir. Optimal bir yığın boyutu, veritabanı commit’lerinin frekansını ve bellek kullanımını dengelemelidir.
* Multi-threaded Step (Paralel Adımlar): Bir Step içindeki okuma, işleme ve yazma işlemlerini birden fazla iş parçacığında paralel olarak çalıştırmayı sağlar. Bu, tek bir makinede CPU ve I/O kaynaklarının daha iyi kullanılmasını sağlar. TaskExecutor kullanılarak yapılandırılır.
* Partitioning (Bölümlendirme): Bir Step‘in verisini mantıksal olarak birden fazla parçaya böler ve her parçayı ayrı bir StepExecution olarak paralel çalıştırmayı sağlar. Bu, aynı makinede veya farklı makinelerde (uzak bölümlendirme) çalıştırılabilir. Veri setinin boyutuna göre işi bölmek için idealdir.
* Remote Chunking (Uzaktan Yığınlama): ItemReader ve ItemProcessor‘ın ana JVM’de çalışırken, ItemWriter‘ın uzak bir işçiye (worker) devredildiği bir modeldir. Bu, yazma işleminin yüksek oranda ölçeklenebilir olmasını sağlar. Genellikle mesaj kuyrukları (JMS, RabbitMQ, Kafka) kullanılarak uygulanır.

Job Listener’lar

Spring Batch, bir Job veya Step‘in yaşam döngüsündeki belirli olaylara (başlangıç, bitiş, hata vb.) tepki vermek için listener’lar sağlar.

* JobExecutionListener: Job başlamadan önce (beforeJob) ve bittikten sonra (afterJob) işlemler yapmak için kullanılır. Örneğin, bir iş başlamadan önce kaynakları hazırlamak veya bittikten sonra sonuçları raporlamak.
* StepExecutionListener: Benzer şekilde, bir Step başlamadan önce (beforeStep) ve bittikten sonra (afterStep) işlemler yapmak için kullanılır.
* ItemReadListener, ItemProcessListener, ItemWriteListener: Okuma, işleme ve yazma aşamalarında her bir öğe veya yığın üzerinde olayları dinlemek için kullanılır. Hata durumlarını yakalamak veya özel loglama yapmak için faydalıdır.

// Örnek JobExecutionListener
package com.example.springbatchexample.listener;

import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.stereotype.Component;

@Component
public class JobCompletionNotificationListener implements JobExecutionListener {

    @Override
    public void beforeJob(JobExecution jobExecution) {
        System.out.println("!!! JOB STARTED! Time: " + jobExecution.getStartTime());
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        if (jobExecution.getStatus().name().equals("COMPLETED")) {
            System.out.println("!!! JOB FINISHED! Time: " + jobExecution.getEndTime());
            System.out.println("Job Status: " + jobExecution.getStatus());
        } else {
            System.out.println("!!! JOB FAILED! Time: " + jobExecution.getEndTime());
            System.out.println("Job Status: " + jobExecution.getStatus());
            System.out.println("Exit Status: " + jobExecution.getExitStatus().getExitDescription());
        }
    }
}

Bu listener’ı BatchConfig‘deki importUserJob‘a eklemek için:

// BatchConfig sınıfında importUserJob bean'ini güncelleyin
@Bean
public Job importUserJob(JobCompletionNotificationListener listener) { // Listener'ı parametre olarak alın
    return new JobBuilder("importUserJob", jobRepository)
            .listener(listener) // Listener'ı ekleyin
            .flow(importStep())
            .end()
            .build();
}

Tasklet Kullanımı

Tasklet, ItemReader, ItemProcessor, ItemWriter döngüsüne uymayan basit görevler için kullanılır. Örneğin, bir batch işlemi başlamadan önce geçici dosyaları temizlemek veya bittikten sonra bir e-posta göndermek gibi görevler için idealdir.

// Örnek Tasklet
package com.example.springbatchexample.tasklet;

import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.stereotype.Component;

import java.io.File;

@Component
public class FileCleanupTasklet implements Tasklet {

    private String filePath = "temp_files/"; // Temizlenecek dosya yolu

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        System.out.println("Cleaning up temporary files in: " + filePath);
        File directory = new File(filePath);
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.delete()) {
                        System.out.println("Deleted: " + file.getName());
                    } else {
                        System.err.println("Failed to delete: " + file.getName());
                    }
                }
            }
        } else {
            System.out.println("Directory does not exist or is not a directory: " + filePath);
        }
        return RepeatStatus.FINISHED;
    }
}

Bu tasklet’ı bir Step olarak kullanmak için BatchConfig‘e ekleyin:

// BatchConfig sınıfında
@Bean
public Step cleanupStep(FileCleanupTasklet fileCleanupTasklet) {
    return new StepBuilder("cleanupStep", jobRepository)
            .tasklet(fileCleanupTasklet, transactionManager)
            .build();
}

@Bean
public Job importUserJob(JobCompletionNotificationListener listener, Step cleanupStep) { // cleanupStep'i de alın
    return new JobBuilder("importUserJob", jobRepository)
            .listener(listener)
            .flow(importStep())
            .next(cleanupStep) // importStep'ten sonra cleanupStep'i çalıştır
            .end()
            .build();
}

Veritabanı Desteği

Örneğimizde H2 in-memory veritabanı kullandık. Ancak üretim ortamlarında, JobRepository‘nin meta verilerini kalıcı olarak saklamak için PostgreSQL, MySQL, Oracle gibi kurumsal veritabanları kullanılır. application.properties dosyasında veritabanı bağlantı bilgilerini değiştirerek kolayca farklı bir veritabanına geçiş yapabilirsiniz. Spring Batch, bu veritabanları için gerekli şemaları otomatik olarak oluşturur veya günceller (spring.batch.jdbc.initialize-schema=always).

Spring Batch Kullanım Senaryoları

Spring Batch’in sunduğu esneklik ve güç, onu çeşitli kurumsal senaryolar için ideal bir çözüm haline getirir:

* ETL (Extract, Transform, Load) Süreçleri: Farklı kaynaklardan (dosyalar, veritabanları, API’ler) veri çekme, iş kurallarına göre dönüştürme ve hedef bir depoya (veri ambarı, başka bir veritabanı) yükleme.
* Finansal Raporlama: Büyük finansal işlem kayıtlarından özet raporlar, bilanço tabloları veya gelir tabloları oluşturma.
* Büyük Veri Setlerinin Migrasyonu: Eski bir sistemden yeni bir sisteme veya farklı bir veritabanı şemasına milyonlarca kaydı güvenli ve verimli bir şekilde taşıma.
* Faturalama ve Ödeme İşlemleri: Müşteri hesaplarını işleme, faturalar oluşturma, ödemeleri kaydetme ve gecikmiş ödemeler için bildirimler gönderme.
* Veri Temizleme ve Doğrulama: Veri setlerindeki tutarsızlıkları, hataları veya eksik bilgileri tespit etme ve düzeltme. Örneğin, yinelenen kayıtları kaldırma veya eksik adres bilgilerini tamamlama.
* Stok Yönetimi: Belirli aralıklarla stok seviyelerini güncelleme, envanter sayımı yapma ve düşük stok uyarıları oluşturma.
* Toplu E-posta/SMS Gönderimi: Büyük bir kullanıcı listesine kişiselleştirilmiş toplu e-postalar veya SMS bildirimleri gönderme.

Bu senaryoların her biri, Spring Batch’in hata yönetimi, yeniden başlatılabilirlik ve ölçeklenebilirlik özelliklerinden önemli ölçüde faydalanır.

Sonuç

Spring Batch, büyük veri setlerini işlemek için güçlü, esnek ve kapsamlı bir framework sunar. Bu makalede, Spring Batch’in temel kavramlarını, bir CSV dosyasından veritabanına veri aktaran pratik bir örneği ve framework’ün gelişmiş özelliklerini (hata yönetimi, ölçeklenebilirlik, listener’lar, tasklet’lar) ele aldık.

Spring Batch’in sunduğu soyutlama katmanları sayesinde geliştiriciler, düşük seviyeli işleme detayları yerine iş mantığına odaklanabilirler. JobRepository aracılığıyla sağladığı meta veri yönetimi, işlemlerin izlenmesini, yönetilmesini ve hata durumunda sorunsuz bir şekilde yeniden başlatılmasını mümkün kılar.

Günümüzün veri yoğun dünyasında, kurumsal uygulamalar genellikle milyonlarca kaydı işleme ihtiyacı duyar. Spring Batch, bu tür zorlu batch işleme gereksinimlerini karşılamak için kanıtlanmış bir çözümdür. Doğru bir şekilde uygulandığında, iş süreçlerinin otomasyonunu sağlayarak verimliliği artırır, hataları azaltır ve işletmelerin büyük veri setlerinden değerli içgörüler elde etmelerine yardımcı olur. Bu nedenle, modern kurumsal mimarilerin vazgeçilmez bir parçası haline gelmiştir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.