Java批处理教程

在当今世界,互联网已经改变了我们的生活方式,其主要原因之一是大多数日常琐事都使用互联网。 这导致可用于处理的大量数据。

其中涉及大量数据的一些示例是处理工资单,银行对帐单,利息计算等。因此,请设想一下,如果所有这些工作都必须手动完成,那么完成这些工作将花费很多时间。

在当前年龄该如何做? 答案是批处理。

1.简介

批处理是对批量数据执行的,无需人工干预,并且可以长时间运行。 它可能是数据或计算密集型的。 批处理作业可以按预定义的时间表运行,也可以按需启动。 另外,由于批处理作业通常是长时间运行的作业,因此在批处理作业中发现了经常检查和从特定故障中重新启动的常见功能。

1.1 Java批处理的历史

Java平台的批处理是作为JSR 352规范(Java EE 7平台的一部分)引入的,它定义了批处理应用程序的编程模型以及运行和管理批处理作业的运行时。

1.2 Java Batch的体系结构

下图显示了批处理的基本组件。

Java批处理的体系结构

批处理应用程序的体系结构解决了批处理问题,例如作业,步骤,存储库,读取器处理器编写器模式,块,检查点,并行处理,流,重试,排序,分区等。

让我们了解架构的流程。

  • 作业存储库包含需要运行的作业。
  • JobLauncher从Job存储库中取出一个作业。
  • 每个工作都包含步骤。 这些步骤是ItemReaderItemProcessorItemWriter
  • 项目读取器是读取数据的一种。
  • 项目处理是一种将基于业务逻辑处理数据的处理。
  • 条目编写器会将数据写回到定义的源。

1.3批处理组件。

现在,我们将尝试详细了解批处理组件。

  • 作业:作业包含整个批处理过程。 它包含一个或多个步骤。 使用作业指定语言(JSL)将作业组合在一起,该语言指定必须执行步骤的顺序。 在JSR 352中,JSL在称为作业XML文件的XML文件中指定。 一项工作基本上就是一个存放步骤的容器。
  • 步骤:步骤是一个域对象,其中包含作业的独立顺序阶段。 步骤包含执行实际处理所需的所有必要逻辑和数据。 根据批处理规范,步骤的定义含糊不清,因为步骤的内容纯粹是特定于应用程序的,并且可以像开发人员想要的那样复杂或简单。 有两种步骤: 面向块和面向任务
  • 作业操作员:它提供了一个界面来管理作业处理的各个方面,包括操作命令(例如开始,重新启动和停止)以及作业存储库命令(例如,检索作业和步骤执行)。
  • 作业存储库:它包含有关当前正在运行的作业的信息以及有关该作业的历史数据。 JobOperator提供用于访问此存储库的API。 JobRepository可以使用数据库或文件系统来实现。

下一节将帮助您了解批处理体系结构的一些常见特征。

1.3工作步骤

步骤是作业的独立阶段。 如上所述,作业中有两种类型的步骤。 我们将在下面尝试详细了解这两种类型。

1.3.1面向块的步骤

块状步骤将一次读取和处理一项,并将结果分组。 然后,当块达到预定义的大小时,将结果存储起来。 当数据集很大时,面向块的处理使存储结果的效率更高。 它包括三个部分。

  • 项读取器从数据源一个接一个地读取输入,该数据源可以是数据库,平面文件,日志文件等。
  • 处理器将根据已定义的业务逻辑逐一处理数据。
  • 编写器将数据分块写入。 块的大小是预定义的并且是可配置的

作为块步骤的一部分,有一些检查点可向框架提供信息以完成块。 如果在块处理期间发生错误,则可以根据最后一个检查点重新开始该过程。

1.3.2面向任务的步骤

除了处理数据源中的项目外,它还执行任务。 其中包括创建或删除目录,移动文件,创建或删除数据库表等。与块步骤相比,任务步骤通常不会长时间运行。

在正常情况下,在需要清理的面向块的步骤之后使用面向任务的步骤。 例如,我们获取日志文件作为应用程序的输出。 块步骤用于处理数据并从日志文件中获取有意义的信息。

然后,使用任务步骤来清理不再需要的较旧的日志文件。

1.3.3并行处理

批处理作业通常执行昂贵的计算操作并处理大量数据。 批处理应用程序可以在两种情况下受益于并行处理。

  • 本质上独立的步骤可以在不同的线程上运行。
  • 面向块的步骤(其中每个项目的处理独立于处理先前项目的结果)可以在多个线程上运行。

批处理有助于完成任务并更快地执行操作以处理海量数据。

2.工具与技术

让我们看看用于构建程序的技术和工具。

  • Eclipse Oxygen.2发布(4.7.2)
  • Java –版本9.0.4
  • 摇篮– 4.3
  • Spring启动– 2.0.1-发布
  • HSQL数据库

3.项目结构

项目结构如下图所示。

Java Batch的项目结构

上面的项目结构使用Gradle。 也可以使用maven创建该项目,并且build.gralde将替换为pom.xml文件。 该项目的结构将稍微延迟使用Maven进行构建。

4.方案目标

作为程序的一部分,我们将尝试使用spring boot创建一个简单的Java批处理应用程序。 该应用程序将执行以下任务。

  1. 读取:–从CSV文件读取员工数据。
  2. 处理数据:–将员工数据转换为全部大写。
  3. 写入:–将已处理的员工数据写回到数据库中。

4.1 Gradle构建

我们正在使用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.8
targetCompatibility = 1.8dependencies {compile("org.springframework.boot:spring-boot-starter-batch")compile("org.hsqldb:hsqldb")testCompile("junit:junit")
}

在上面的build.gradle文件中, apply plugin: 'java'告诉我们需要设置的插件。 对我们来说,它是Java插件。
repositories{}让我们知道应该从中提取依赖关系的存储库。 我们选择了mavenCentral拉依赖罐。 我们还可以使用jcenter提取相应的依赖罐。

dependencies {}标签用于提供应为项目提取的必要的jar文件详细信息。 apply plugin: 'org.springframework.boot'此插件用于指定spring-boot项目。 boot jar{}将指定将从构建生成的jar的属性。

4.2样本数据文件

为了提供读取阶段的数据,我们将使用包含员工数据的CSV文件。

该文件将如下所示。

样本CSV文件

John,Foster
Joe,Toy
Justin,Taylor
Jane,Clark
John,Steve

示例数据文件包含员工的名字和姓氏。 我们将使用相同的数据进行处理,然后将其插入数据库。

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;}@Overridepublic String toString() {return "firstName: " + firstName + ", lastName: " + lastName;}}

@Override用于覆盖toString()方法的默认实现。

4.5配置类

我们将创建一个BatchConfiguration.java类,它将作为批处理的配置类。 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
@EnableBatchProcessing
public class BatchConfiguration {@Autowiredpublic JobBuilderFactory jobBuilderFactory;@Autowiredpublic StepBuilderFactory stepBuilderFactory;// tag::readerwriterprocessor[]@Beanpublic 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();}@Beanpublic EmployeeItemProcessor processor() {return new EmployeeItemProcessor();}@Beanpublic 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[]@Beanpublic Job importUserJob(JobCompletionNotificationListener listener, Step step1) {return jobBuilderFactory.get("importUserJob").incrementer(new RunIdIncrementer()).listener(listener).flow(step1).end().build();}@Beanpublic Step step1(JdbcBatchItemWriter writer) {return stepBuilderFactory.get("step1").<Employee, Employee> chunk(10).reader(reader()).processor(processor()).writer(writer).build();}// end::jobstep[]
}

@EnableBatchProcessing批注用于启用批处理。
JobBuilderFactory是用于构建作业的工厂。
StepBuilderFactory用于创建步骤。 方法step1()具有属性chunk() 。 这是用于将输入分块为定义大小的属性。 对于我们来说,大小为10。

4.6项目处理器

项目处理器是一个接口,将负责处理数据。 我们将在EmployeeItemProcessor.java实现该接口。 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);@Overridepublic 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;@Component
public 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批处理程序的main方法。 该类如下所示。

应用程序

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

@SpringBootApplication是用于将程序指定为Spring Boot程序的注释。

5.输出

让我们将该应用程序作为Java应用程序执行。 我们将在控制台上获得以下输出。

JavaBatch程序的输出

批处理程序的工作流在输出中非常清楚。 Job以importUserJob ,然后第一步执行开始,将读取的数据转换为大写。

步骤的后处理,我们可以在控制台上看到大写的结果。

6.总结

在本教程中,我们学习了以下内容:

  1. Java批处理包含作业,该作业可以包含多个步骤。
  2. 每一步都是阅读,处理,写作的结合。
  3. 我们可以将数据分块为不同大小以进行处理。

7.下载Eclipse项目

这是带有SpringBoot的JavaBatch教程。

您可以在此处下载此示例的完整源代码: JavaBatch.zip

翻译自: https://www.javacodegeeks.com/2018/05/java-batch-tutorial.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346924.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

编写junit 测试_使用JUnit和Repeat注​​释编写有效的负载测试

编写junit 测试EasyTest最近推出了一组新的注释&#xff0c;可帮助其用户编写有效的测试用例。 进入EasyTest的两个主要注释是&#xff1a; 重复 持续时间 今天&#xff0c;我们将讨论重复标注。 一种新的方法级别注释 重复已添加到EasyTest Framework。 此批注可用于重复…

【数字信号处理】基于DFT的滤波系列3之插值滤波(含MATLAB代码)

四、基于DFT的(理想)滤波 例2:一个“警告” “理想DFT滤波器”虽然简单、有效,但可能会导致意想不到的问题。在博客 【数字信号处理】基于DFT的滤波系列2(含MATLAB代码) 中,数据本身是理想的,由完美的谐波组成,这些谐波在频域中以单一频率理想地表示(无频谱泄漏),这…

【数字信号处理】基于DFT的滤波系列4之加窗(含MATLAB代码)

四、基于DFT的(理想)滤波 加窗以减少频谱泄漏 在上面的例子中,整数次谐波被用来产生理想中的示例。这意味着一个完整的整数周期适合正在使用的样本数。一个明显的问题是,如果使用非整数周期数(以及谐波)会怎样?答案是远没有那么有效。 在现实世界中,从这个意义上说,数…

【数字信号处理】基于DFT的滤波系列5之二维DFT滤波(含MATLAB代码)

五、二维DFT滤波 前几节介绍的用于对时间序列滤波的原理也可用于对图像的滤波,采用二维傅里叶变换技术。 下图为一幅图像的二维DFT(2D DFT)变换后的幅度值,该图像仅由一个恒定强度组成,因此它是0Hz分量——背景强度。在可视化 2D DFT 的结果时通常使用fftshift(),因此 DC…

Vaadin教程

1.简介 当您是后端开发人员时&#xff0c;您会听到人们说您无法创建内置HTML的UI页面并且无法使用CSS设置样式时所引起的痛苦。 就像成为后端开发人员一样&#xff0c;它具有已知的局限性&#xff0c;即我们可以播放和运行大型生产后端应用程序&#xff0c;但不能创建漂亮的页面…

jee web_您基于JEE的Web项目的结构是什么?

jee web在这篇文章中&#xff0c;我将尝试讨论基于Web的项目的各种组织结构&#xff0c;主要是使用JSF。 开始新项目时&#xff0c;首先想到的是如何组织Java包&#xff1f; 想象一下&#xff0c;您开发了一个基于Web的用户和组管理系统。 很长时间以来&#xff0c;我使用了以下…

开源mindmap_Java开发人员访谈的MindMap

开源mindmap多年来&#xff0c;我在许多Java开发人员的访谈中担任小组成员。 之前&#xff0c;我曾写过一篇标题为成功参加软件工程师技术面试的7大技巧的文章&#xff0c;其中涵盖了很少的一般准则。 在本文中&#xff0c;我将分享一个思维导图&#xff0c;其中包含Java开发人…

【数字信号处理】希尔伯特变换系列2之基于定向多普勒超声的胎儿心率监测(含MATLAB代码)

希尔伯特变换的应用 希尔伯特变换在许多工程应用中都有使用,此处主要介绍两种用法。 首先,它解决了多普勒超声胎儿心率监测器中出现的运动方向不明确的问题。第二,它与众所周知的解析信号联系起来了,在极坐标中,它能够找到信号的瞬时幅度和瞬时频率。 基于定向多普勒超…

轻松地与Java完全集成

这里介绍了如何编写完整的堆栈数据库Web应用程序&#xff0c;而无需使用SQL&#xff0c;HQL&#xff0c;PHP&#xff0c;ASP&#xff0c;HTML&#xff0c;CSS或Javascript&#xff0c;而是使用Vaadin的UI层和Speedment Stream ORM完全依赖Java。 是否曾经想过快速创建连接到您…

【自适应盲均衡11】基于Volterra级数的双线性CMA盲均衡算法与MATLAB仿真(采用16QAM信号模型)

结果预览 16QAM信号的星座图: 输入信号的星座图: Volterra-CMA盲均衡算法的MSE曲线: 均衡后的星座图: 一、Volterra级数 由于多方面的原因,Volterra级数模型是非线性系统广泛采用的模型。简单起见,本文仍采用线性系统进行测试。 Volterra级数展开是由非递归级数组成…

矩形和升余弦成型下OQPSK信号的调制与解调仿真(最大功率法定时)

关注公号【逆向通信猿】更精彩!!! 仿真结果预览 OQPSK矩形和升余弦成型误码率曲线: 关于QPSK信号的仿真在之前的博客里已经 一、OQPSK调制原理 在QPSK体制中,它的相邻码元最大相位差达到180。由于这样的相位突变在频带受限的系统中会引起信号包络的很大起伏,这是不希…

VB语言与测量程序设计之水准网平差程序(任务8-3含代码,完整工程文件见CSDN资源)

一、程序总体设计 二、程序界面设计 对象属性设置 三、程序代码 矩阵计算类代码 文件名:Matrix.cls 操作矩阵的类 Matrix Option Explicit Const eps As Double = 0.00000001 缺省精度 Dim nRo

Gradle教程

1.简介 在本课程中&#xff0c;我们将学习Gradle &#xff0c;它是一个构建工具和一个依赖管理系统&#xff0c;与Maven和Ant非常相似&#xff0c;并且是专门为构建基于Java的项目而设计的。 与Maven和Ant构建系统不同&#xff0c;Gradle不使用XML。 它实际上是基于Groovy构建…

【定时同步系列6】Gardener误差检测算法原理

关注公号【逆向通信猿】更精彩!!! 引言 离散时间符号定时同步方法 如下图所示为比较常用的一种符号定时同步的离散时间方法,通常由三个基本单元组成离散时间锁相环,分别为:定时误差检测器(TED)、环路滤波器和插值控制。其中,插值器和TED作用相当于鉴相器,插值控制相…

【数字信号处理】卷积和乘法系列3之测不准原理

关注公号【逆向通信猿】更精彩!!! 声明:底部的小广告标签并不是博主所加!! Heisenberg测不准原理 信息在时域中的扩展(尖峰之间的距离)与其在频域中的对应扩展之间的这种关系是Heisenberg不确定性原理的一个例子。时域中的扩展(方差)乘以频域中的扩展具有不能被突破的…

【数字信号处理】卷积和乘法系列3之傅里叶变换对II

关注公号【逆向通信猿】更精彩!!! 声明:底部的小广告标签并不是博主所加!! 采样 傅里叶变换对(FT)很重要的原因是,如果有一个连续时间 (CT) 信号,则可以通过将信号乘以梳状函数来对其进行采样,产生的样本将只是尖峰处的值。采样过程产生离散时间 (DT) 信号,因为采…

【定时同步系列8】QPSK基带调制+Gardener定时误差检测+解调误码率曲线之MATLAB并行仿真姊妹篇一

结果预览 误码率曲线 关于反馈型定时同步技术的原理已经陆陆续续讨论了好久了,涉及的各个细节内容较多,且不容易理解,整个流程框图如下所示: 符号定时同步的离散时间方法(异步) 其中, interpolator模块在博客: 【定时同步系列5】Farrow内插器结构原理和MATLAB实现 TED模…

eclipse 隐藏项目_前5个有用的隐藏Eclipse功能

eclipse 隐藏项目Eclipse是野兽。 仅凭其力量才能超越其神秘感的设备。 有人将其称为连续体跨功能器 。 其他人则称它为透湿器 。 是的&#xff0c;它是如此之大&#xff0c;需要花费数年才能掌握。 然后&#xff0c;您的经理出现并告诉您&#xff1a;我们正在使用NetBeans。 …

使用Spring Security和OAuth 2.0保护Spring微服务架构

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 每个开发人员都希望能够更快&#xff0c;更有效地进行构建以支持规模。 使用Spring构…

一种使用setdll+HOOK钩子技术+dll为MFC程序ProtocalTool等老旧程序打补丁的思路(含源码)

一、引言 由于工作原因,需要使用一个很老旧的软件,没有源代码,该软件在XP系统下运行正常,但是需要登录,且在win10系统下使用时IP控件运行不正常,只能输入每个数字只能输入2位数,还有一些其他问题,比如给软件添加一些编辑框,或者对软件进行 下面简单梳理一下解决这些…