Java Batch Tutorial

今日の世界でインターネットは私たちの生活の方法を変え、その大きな理由の1つは、毎日の雑用のほとんどにインターネットが使用されているためです。 3313>

膨大なデータを扱う例としては、給与明細、銀行明細、利息計算などの処理が挙げられます。 もし、これらの仕事をすべて手作業で行わなければならないとしたら、これらの仕事を終えるのに何年もかかるでしょう。

現代ではどのように行われているのでしょうか。

はじめに

バッチ処理はバルクデータに対して行われ、人手を介さず、長時間にわたって実行される。 データまたは計算を大量に必要とする場合があります。 バッチジョブは事前に定義されたスケジュールで実行することも、要求に応じて開始することもできます。 また、バッチジョブは通常、長時間実行されるジョブであるため、一定のチェックと特定の障害からの再開がバッチジョブに見られる一般的な機能である

1.1 Javaバッチ処理の歴史

Javaプラットフォームのバッチ処理は、Java EE 7プラットフォームの一部であるJSR 352仕様の一部として導入され、バッチアプリケーションのプログラミングモデルに加えて、バッチジョブを実行および管理するランタイムを定義する。

1.2 Javaバッチのアーキテクチャ

以下の図にバッチ処理の基本コンポーネントを示す。

Java バッチ処理のためのアーキテクチャ

バッチアプリケーションのためのアーキテクチャは、ジョブ、ステップ、リポジトリ、リーダープロセッサ、ライターパターン、チャンク、チェックポイント、並列処理、フロー、リトライ、シーケンス、パーティショニングなどのバッチ処理に関する問題を解決する。

  • ジョブリポジトリには、実行する必要があるジョブが格納されています。
  • JobLauncher は、ジョブリポジトリからジョブを取り出します。
  • Item Readerはデータを読み込むものです。
  • Item Processはビジネスロジックに基づいてデータを処理するものです。
  • アイテムライターは、定義されたソースにデータを書き戻します。

1.3 バッチ処理コンポーネント

ここで、バッチ処理コンポーネントを詳しく理解しましょう。 ジョブは、バッチ処理全体を構成するものです。 1つまたは複数のステップが含まれます。 ジョブは、ステップの実行順序を指定するJob Specification Language (JSL)を使ってまとめられる。 JSR352では、JSLはジョブXMLファイルとして知られるXMLファイルで指定される。 ジョブは基本的にステップを保持するコンテナである

  • ステップ。 ステップとは、ジョブの独立した連続したフェーズを含むドメインオブジェクトである。 ステップには実際の処理を実行するために必要なロジックとデータがすべて含まれている。 ステップの内容は純粋にアプリケーション固有であり、開発者が望むように複雑でも単純でもよいため、ステップの定義はバッチ仕様のように曖昧に保たれる。 ステップには、チャンク型とタスク型の2種類がある。 ジョブ処理のあらゆる側面を管理するインターフェースを提供する。これには、開始、再起動、停止などの操作コマンド、およびジョブやステップの実行結果の取得などのジョブ・リポジトリ・コマンドが含まれる。 現在実行中のジョブの情報や、そのジョブに関する履歴データが格納されています。 JobOperator はこのリポジトリにアクセスするためのAPIを提供します。
  • 以下のセクションは、バッチアーキテクチャの一般的な特徴を理解するのに役立ちます。

    1.3 ジョブのステップ

    ステップは、ジョブの独立したフェーズです。 上述したように、ジョブのステップには2つのタイプがあります。

    1.3.1 チャンク指向ステップ

    チャンクステップは一度に1つのアイテムを読み込んで処理し、その結果をチャンクにまとめます。 そして、チャンクがあらかじめ定義されたサイズに達すると、結果が格納されます。 チャンク指向処理は、データセットが巨大な場合に結果の保存をより効率的にする。

    • アイテムリーダーは、データベース、フラットファイル、ログファイルなどのデータソースから次々と入力を読み取る。
    • プロセッサは、定義されたビジネスロジックに基づいてデータを1つずつ処理する。 チャンクのサイズはあらかじめ定義されており、設定可能です

    チャンクのステップの一部として、チャンクの完了のための情報をフレームワークに提供するチェックポイントがあります。

    1.3.2 タスク指向ステップ

    これは、データソースからのアイテムの処理以外のタスクを実行するものです。 ディレクトリの作成・削除、ファイルの移動、データベーステーブルの作成・削除などが含まれます。

    通常のシナリオでは、タスク指向のステップは、クリーンアップが必要なチャンク指向のステップの後に使用されます。 たとえば、アプリケーションの出力としてログファイルを取得します。

    1.3.3 並列処理

    バッチジョブはしばしば高価な計算処理を実行し、大量のデータを処理します。 バッチアプリケーションは、2つのシナリオで並列処理の恩恵を受けることができます。

    • 本質的に独立したステップは、異なるスレッドで実行できます。
    • 各項目の処理が前の項目の処理結果から独立しているジャンク指向のステップは、複数のスレッドで実行できます。

    バッチ処理は、巨大なデータに対してより速くタスクを完了し、処理を実行するのに役立ちます。

    ツールとテクノロジー

    プログラム構築に使用したテクノロジーとツールを見てみましょう。 Release (4.7.2)

  • Java – version 9.0.4
  • Gradle- 4.3
  • Spring boot – 2.0.1-Release
  • HSQL Database
  • プロジェクトの構造

    プロジェクトの構造は下の画像のようになる予定です。

    Java Batchのプロジェクト構造

    上記のプロジェクト構造は、Gradleを使用しています。 このプロジェクトは、maven を使用して作成することもでき、build.gralde は pom.xml ファイルに置き換えられます。

    An objective of the Program

    As a part of the program, we will try to create a simple java batch application using spring boot.プロジェクトの構造は、ビルドにMavenを使用することで若干延期されるでしょう。 このアプリケーションは、次のタスクを実行します。

    1. 読み込み: – CSVファイルから社員データを読み込みます。
    2. データを処理します。 – 従業員データをすべて大文字に変換します。 – 処理した社員データをデータベースに書き戻す.

    4.1 Gradle build

    プログラムの一部として、ビルドにGradleを使用しています。 build.gradle ファイルは以下のようになります。

    build.gradle

    buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE") }}apply plugin: 'java'apply plugin: 'eclipse'apply plugin: 'idea'apply plugin: 'org.springframework.boot'apply plugin: 'io.spring.dependency-management'bootJar { baseName = 'java-batch' version = '1.0'}repositories { mavenCentral()}sourceCompatibility = 1.8targetCompatibility = 1.8dependencies { compile("org.springframework.boot:spring-boot-starter-batch") compile("org.hsqldb:hsqldb") testCompile("junit:junit")}

    上記の build.gradle ファイルで apply plugin: 'java' は設定する必要があるプラグインを示します。
    repositories{} は依存関係が引き出されるべきリポジトリを知らせています。 私たちは、依存関係の jar を取得するために mavenCentral を選択しました。 jcenter もそれぞれの依存性 jar を取得するために使用できます。

    dependencies {} タグは、プロジェクトに取得する必要がある jar ファイルの詳細を提供するために使用されます。 apply plugin: 'org.springframework.boot' このプラグインは、spring-boot プロジェクトを指定するために使用されます。 boot jar{} は、ビルドから生成される jar のプロパティを指定します。

    4.2 サンプル データ ファイル

    読み取りフェーズにデータを提供するために、従業員データを含む CSV ファイルを使用します。

    4.3 SQLスクリプト

    メモリベースのデータベースであるHSQLデータベースを使用しています。

    SQL スクリプト

    DROP TABLE employee IF EXISTS;CREATE TABLE employee ( person_id BIGINT IDENTITY NOT NULL PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20));

    Spring Boot は起動時に schema-@@platform@@.sql を自動的に実行します。 -allはすべてのプラットフォームでデフォルトです。 そのため、テーブルの作成はアプリケーションの起動時に勝手に行われ、アプリケーションが稼働するまで利用できます。

    4.4 モデルクラス

    モデルクラスとしてEmployee.javaクラスを作成することにします。

    プログラムのモデルクラス

    package com.batch;public class Employee { private String lastName; private String firstName; public Employee() { } public Employee(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Override public String toString() { return "firstName: " + firstName + ", lastName: " + lastName; }}

    @Override は、toString()メソッドのデフォルト実装をオーバーライドするために使用します。

    4.5 設定クラス

    バッチ処理用の設定クラスとなる BatchConfiguration.java クラスを作成する予定です。

    BatchConfiguration.java

    package com.batch.config;import javax.sql.DataSource;import org.springframework.batch.core.Job;import org.springframework.batch.core.JobExecutionListener;import org.springframework.batch.core.Step;import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;import org.springframework.batch.core.launch.support.RunIdIncrementer;import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;import org.springframework.batch.item.database.JdbcBatchItemWriter;import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;import org.springframework.batch.item.file.FlatFileItemReader;import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;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.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.ClassPathResource;import org.springframework.jdbc.core.JdbcTemplate;import com.batch.Employee;import com.batch.processor.EmployeeItemProcessor;@Configuration@EnableBatchProcessingpublic class BatchConfiguration { @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; // tag::readerwriterprocessor @Bean public FlatFileItemReader reader() { return new FlatFileItemReaderBuilder() .name("EmployeeItemReader") .resource(new ClassPathResource("sample-data.csv")) .delimited() .names(new String{"firstName", "lastName"}) .fieldSetMapper(new BeanWrapperFieldSetMapper() {{ setTargetType(Employee.class); }}) .build(); } @Bean public EmployeeItemProcessor processor() { return new EmployeeItemProcessor(); } @Bean public JdbcBatchItemWriter writer(DataSource dataSource) { return new JdbcBatchItemWriterBuilder() .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>()) .sql("INSERT INTO employee (first_name, last_name) VALUES (:firstName, :lastName)") .dataSource(dataSource) .build(); } // end::readerwriterprocessor // tag::jobstep @Bean public Job importUserJob(JobCompletionNotificationListener listener, Step step1) { return jobBuilderFactory.get("importUserJob") .incrementer(new RunIdIncrementer()) .listener(listener) .flow(step1) .end() .build(); } @Bean public Step step1(JdbcBatchItemWriter writer) { return stepBuilderFactory.get("step1") .<Employee, Employee> chunk(10) .reader(reader()) .processor(processor()) .writer(writer) .build(); } // end::jobstep}

    @EnableBatchProcessing アノテーションはバッチ処理を有効にするために使用します。
    JobBuilderFactoryはジョブの構築に使用するファクトリーです。 これは、入力を定義されたサイズにチャンキングするために使用されるプロパティです。

    4.6 Item Processor

    Itemプロセッサは、データの処理を担当するインターフェースである。 このインターフェイスをEmployeeItemProcessor.javaで実装する。

    EmployeeItemProcessor.java

    package com.batch.processor;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.batch.item.ItemProcessor;import com.batch.Employee;public class EmployeeItemProcessor implements ItemProcessor<Employee, Employee> { private static final Logger log = LoggerFactory.getLogger(EmployeeItemProcessor.class); @Override public Employee process(Employee emp) throws Exception { final String firstName = emp.getFirstName().toUpperCase(); final String lastName = emp.getLastName().toUpperCase(); final Employee transformedEmployee = new Employee(firstName, lastName); log.info("Converting (" + emp + ") into (" + transformedEmployee + ")"); return transformedEmployee; }}

    process()メソッドでデータを取得し、大文字の名前に変換します。

    4.7 JobExecutionSupportListenerクラス

    JobExecutionListenerSupport ジョブが終了すると通知を行うためのインターフェイスです。 インターフェイスの一部として、afterJobメソッドがあります。

    JobCompletionNotificationListener.java

    package com.batch.config;import java.util.List;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.batch.core.BatchStatus;import org.springframework.batch.core.JobExecution;import org.springframework.batch.core.listener.JobExecutionListenerSupport;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import org.springframework.stereotype.Component;import com.batch.Employee;@Componentpublic class JobCompletionNotificationListener extends JobExecutionListenerSupport {private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);private final JdbcTemplate jdbcTemplate;@Autowiredpublic JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic void afterJob(JobExecution jobExecution) {RowMapper rowMapper = (rs, rowNum) -> {Employee e = new Employee();e.setFirstName(rs.getString(1));e.setLastName(rs.getString(2));return e;};if(jobExecution.getStatus() == BatchStatus.COMPLETED) {log.info("!!! JOB FINISHED! Time to verify the results");List empList= jdbcTemplate.query("SELECT first_name, last_name FROM employee",rowMapper);log.info("Size of List "+empList.size());for (Employee emp: empList) {log.info("Found: "+emp.getFirstName()+" "+emp.getLastName());}}}}

    このメソッドでは、ジョブの完了後にデータベースからデータを取得し、データに対して実行された処理を確認するためにコンソールに結果を表示しています。

    4.8 アプリケーションクラス

    Javaバッチプログラムを起動するメインメソッドを含むアプリケーションクラスを作成する予定です。

    Application.java

    package com.batch;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application { public static void main(String args) throws Exception { SpringApplication.run(Application.class, args); }}

    @SpringBootApplicationは、プログラムをSpring Bootプログラムとして指定するためのアノテーションです。

    Output

    Javaアプリケーションとして実行してみましょう。 コンソールに以下のような出力が得られます。

    The output of JavaBatch program

    バッチプログラムのワークフローは、出力から非常にわかりやすく入手できます。

    ステップ処理の後、コンソールで大文字の結果を見ることができます。

    まとめ

    このチュートリアルでは、次のことを学びました:

    1. Javaバッチには複数のステップを含むことができるジョブがあります。
    2. 各ステップは、読み取り、処理、書き込みの組み合わせです。
    3. データを異なるサイズに切り出して処理することができます。 Eclipseプロジェクトのダウンロード

      SpringBootによるJavaBatchのチュートリアルだった