<article class=“article fmt article-content”><p>原题目:Spring认证指南-理解如何创立根本的批处理驱动解决方案(Spring中国教育管理中心)</p><p>Spring认证指南:理解如何创立根本的批处理驱动解决方案<br/>创立批处理服务<br/>本指南将疏导您实现创立根本批处理驱动解决方案的过程。</p><p>你将建造什么<br/>您将构建一个从 CSV 电子表格导入数据、应用自定义代码对其进行转换并将最终后果存储在数据库中的服务。</p><p>你须要什么<br/>约15分钟<br/>最喜爱的文本编辑器或 IDE<br/>JDK 1.8或更高版本<br/>Gradle 4+或Maven 3.2+<br/>您还能够将代码间接导入 IDE:<br/>弹簧工具套件 (STS)<br/>IntelliJ IDEA<br/>如何实现本指南<br/>像大多数 Spring入门指南一样,您能够从头开始并实现每个步骤,也能够绕过您曾经相熟的根本设置步骤。无论哪种形式,您最终都会失去工作代码。</p><p>要从头开始,请持续从 Spring Initializr 开始。</p><p>要跳过基础知识,请执行以下操作:</p><p>下载并解压本指南的源代码库,或应用Git克隆它:git clone https://github.com/spring-gui...<br/>光盘进入gs-batch-processing/initial<br/>持续创立商务舱。<br/>实现后,您能够对照中的代码查看后果<br/>gs-batch-processing/complete。</p><p>业务数据<br/>通常,您的客户或业务分析师会提供电子表格。对于这个简略的示例,您能够在以下地位找到一些虚构的数据<br/>src/main/resources/sample-data.csv:</p><p>Jill,Doe</p><p>Joe,Doe</p><p>Justin,Doe</p><p>Jane,Doe</p><p>John,Doe</p><p>此电子表格的每一行都蕴含名字和姓氏,以逗号分隔。这是一种相当常见的模式,Spring 无需定制即可解决。</p><p>接下来,您须要编写一个 SQL 脚本来创立一个表来存储数据。您能够在以下地位找到这样的脚本<br/>src/main/resources/schema-all.sql:</p><p>DROP TABLE people IF EXISTS;</p><p>CREATE TABLE people (</p><p>person_id BIGINT IDENTITY NOT NULL PRIMARY KEY,</p><p>first_name VARCHAR(20),</p><p>last_name VARCHAR(20)</p><p>);</p><p>Spring Bootschema-@@platform@@.sql在启动期间主动运行。-all是所有平台的默认设置。</p><p>从 Spring Initializr 开始<br/>您能够应用这个事后初始化的我的项目并单击 Generate 下载 ZIP 文件。此我的项目配置为适宜本教程中的示例。</p><p>手动初始化我的项目:</p><p>导航到https://start.spring.io。该服务提取应用程序所需的所有依赖项,并为您实现大部分设置。<br/>抉择 Gradle 或 Maven 以及您要应用的语言。本指南假设您抉择了 Java。<br/>单击Dependencies并抉择Spring Batch和HyperSQL Database。<br/>单击生成。<br/>下载生成的 ZIP 文件,该文件是依据您的抉择配置的 Web 应用程序的存档。<br/>如果您的 IDE 具备 Spring Initializr 集成,您能够从您的 IDE 实现此过程。</p><p>你也能够从 Github 上 fork 我的项目并在你的 IDE 或其余编辑器中关上它。</p><p>创立商务舱<br/>当初您能够看到数据输出和输入的格局,您能够编写代码来示意一行数据,如以下示例(来自<br/>src/main/java/com/example/batchprocessing/Person.java)所示:</p><p>package com.example.batchprocessing;</p><p>public class Person {</p><p>private String lastName;</p><p>private String firstName;</p><p>public Person() {</p><p>}</p><p>public Person(String firstName, String lastName) {</p><p>this.firstName = firstName;</p><p>this.lastName = lastName;</p><p>}</p><p>public void setFirstName(String firstName) {</p><p>this.firstName = firstName;</p><p>}</p><p>public String getFirstName() {</p><p>return firstName;</p><p>}</p><p>public String getLastName() {</p><p>return lastName;</p><p>}</p><p>public void setLastName(String lastName) {</p><p>this.lastName = lastName;</p><p>}</p><p>@Override</p><p>public String toString() {</p><p>return “firstName: " + firstName + “, lastName: " + lastName;</p><p>}</p><p>}</p><p>创立两头处理器<br/>批处理中的一个常见范例是摄取数据,对其进行转换,而后将其通过管道输入到其余中央。在这里,您须要编写一个简略的转换器,将名称转换为大写。以下清单(来自<br/>src/main/java/com/example/batchprocessing/PersonItemProcessor.java)显示了如何执行此操作:</p><p>package com.example.batchprocessing;</p><p>import org.slf4j.Logger;</p><p>import org.slf4j.LoggerFactory;</p><p>import org.springframework.batch.item.ItemProcessor;</p><p>public class PersonItemProcessor implements ItemProcessor<Person, Person> {</p><p>private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class);</p><p>@Override</p><p>public Person process(final Person person) throws Exception {</p><p>final String firstName = person.getFirstName().toUpperCase();</p><p>final String lastName = person.getLastName().toUpperCase();</p><p>final Person transformedPerson = new Person(firstName, lastName);</p><p>log.info(“Converting (” + person + “) into (” + transformedPerson + “)”);</p><p>return transformedPerson;</p><p>}</p><p>}</p><p>PersonItemProcessor实现 Spring Batch 的ItemProcessor接口。这使得将代码连贯到您将在本指南前面定义的批处理作业变得很容易。依据界面,您会收到一个传入的Person对象,而后将其转换为大写的Person.</p><p>输出和输入类型不用雷同。事实上,在读取一个数据源之后,有时应用程序的数据流须要不同的数据类型。</p><p>将批处理作业放在一起<br/>当初您须要将理论的批处理作业放在一起。Spring Batch 提供了许多实用程序类来缩小编写自定义代码的须要。相同,您能够专一于业务逻辑。</p><p>要配置您的作业,您必须首先创立一个 Spring@Configuration类,如下例所示<br/>src/main/java/com/exampe/batchprocessing/BatchConfiguration.java:</p><p>@Configuration</p><p>@EnableBatchProcessing</p><p>public class BatchConfiguration {</p><p>@Autowired</p><p>public JobBuilderFactory jobBuilderFactory;</p><p>@Autowired</p><p>public StepBuilderFactory stepBuilderFactory;</p><p>…</p><p>}</p><p>对于初学者,@EnableBatchProcessing正文增加了许多反对作业并为您节俭大量工作的要害 bean。此示例应用基于内存的数据库(由 提供@EnableBatchProcessing),这意味着实现后,数据就隐没了。它还主动连贯上面须要的几个工厂。当初将以下 bean 增加到您的BatchConfiguration类中以定义读取器、处理器和写入器:</p><p>@Bean</p><p>public FlatFileItemReader<Person> reader() {</p><p>return new FlatFileItemReaderBuilder<Person>()</p><p>.name(“personItemReader”)</p><p>.resource(new ClassPathResource(“sample-data.csv”))</p><p>.delimited()</p><p>.names(new String[]{“firstName”, “lastName”})</p><p>.fieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{</p><p>setTargetType(Person.class);</p><p>}})</p><p>.build();</p><p>}</p><p>@Bean</p><p>public PersonItemProcessor processor() {</p><p>return new PersonItemProcessor();</p><p>}</p><p>@Bean</p><p>public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {</p><p>return new JdbcBatchItemWriterBuilder<Person>()</p><p>.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())</p><p>.sql(“INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)”)</p><p>.dataSource(dataSource)</p><p>.build();</p><p>}</p><p>第一段代码定义了输出、处理器和输入。</p><p>reader()创立一个ItemReader. 它查找一个名为的文件sample-data.csv,并应用足够的信息解析每个行我的项目,以将其转换为Person.<br/>processor()创立一个PersonItemProcessor您之前定义的实例,用于将数据转换为大写。<br/>writer(DataSource)创立一个ItemWriter. 这个针对 JDBC 指标,并主动获取由@EnableBatchProcessing. 它包含插入单个 所需的 SQL 语句Person,由 Java bean 属性驱动。<br/>最初一个块(来自<br/>src/main/java/com/example/batchprocessing/BatchConfiguration.java)显示了理论的作业配置:</p><p>@Bean</p><p>public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {</p><p>return jobBuilderFactory.get(“importUserJob”)</p><p>.incrementer(new RunIdIncrementer())</p><p>.listener(listener)</p><p>.flow(step1)</p><p>.end()</p><p>.build();</p><p>}</p><p>@Bean</p><p>public Step step1(JdbcBatchItemWriter<Person> writer) {</p><p>return stepBuilderFactory.get(“step1”)</p><p>.<Person, Person> chunk(10)</p><p>.reader(reader())</p><p>.processor(processor())</p><p>.writer(writer)</p><p>.build();</p><p>}</p><p>第一种办法定义了作业,第二种办法定义了一个步骤。作业是由步骤构建的,其中每个步骤都可能波及读取器、处理器和写入器。</p><p>在此作业定义中,您须要一个增量器,因为作业应用数据库来保护执行状态。而后列出每个步骤(只管此作业只有一个步骤)。作业完结,Java API 生成一个完满配置的作业。</p><p>在步骤定义中,您定义一次写入多少数据。在这种状况下,它一次最多写入十个记录。接下来,您应用之前注入的 bean 配置读取器、处理器和写入器。</p><p>chunk()是前缀<Person,Person>,因为它是一个通用办法。这示意每个解决“块”的输出和输入类型,并与ItemReader<Person>和对齐ItemWriter<Person>。</p><p>批处理配置的最初一点是在作业实现时取得告诉的一种形式。以下示例(来自<br/>src/main/java/com/example/batchprocessing/JobCompletionNotificationListener.java)显示了这样一个类:</p><p>package com.example.batchprocessing;</p><p>import org.slf4j.Logger;</p><p>import org.slf4j.LoggerFactory;</p><p>import org.springframework.batch.core.BatchStatus;</p><p>import org.springframework.batch.core.JobExecution;</p><p>import org.springframework.batch.core.listener.JobExecutionListenerSupport;</p><p>import org.springframework.beans.factory.annotation.Autowired;</p><p>import org.springframework.jdbc.core.JdbcTemplate;</p><p>import org.springframework.stereotype.Component;</p><p>@Component</p><p>public class JobCompletionNotificationListener extends JobExecutionListenerSupport {</p><p>private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);</p><p>private final JdbcTemplate jdbcTemplate;</p><p>@Autowired</p><p>public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {</p><p>this.jdbcTemplate = jdbcTemplate;</p><p>}</p><p>@Override</p><p>public void afterJob(JobExecution jobExecution) {</p><p>if(jobExecution.getStatus() == BatchStatus.COMPLETED) {</p><p>log.info(”!!! JOB FINISHED! Time to verify the results”);</p><p>jdbcTemplate.query(“SELECT first_name, last_name FROM people”,</p><p>(rs, row) -> new Person(</p><p>rs.getString(1),</p><p>rs.getString(2))</p><p>).forEach(person -> log.info(“Found <” + person + “> in the database.”));</p><p>}</p><p>}</p><p>}</p><p>JobCompletionNotificationListener监听作业的工夫,BatchStatus.COMPLETED而后用于JdbcTemplate查看后果。</p><p>使应用程序可执行<br/>只管批处理能够嵌入到 Web 应用程序和 WAR 文件中,但上面演示的更简略的办法能够创立一个独立的应用程序。您将所有内容打包在一个可执行的 JAR 文件中,由一个很好的旧 Javamain()办法驱动。</p><p>Spring Initializr 为您创立了一个应用程序类。对于这个简略的示例,它无需进一步批改即可工作。以下清单(来自<br/>src/main/java/com/example/batchprocessing/BatchProcessingApplication.java)显示了应用程序类:<br/>JobCompletionNotificationListener监听作业的工夫,BatchStatus.COMPLETED而后用于JdbcTemplate查看后果。</p><p>使应用程序可执行<br/>只管批处理能够嵌入到 Web 应用程序和 WAR 文件中,但上面演示的更简略的办法能够创立一个独立的应用程序。您将所有内容打包在一个可执行的 JAR 文件中,由一个很好的旧 Javamain()办法驱动。</p><p>Spring Initializr 为您创立了一个应用程序类。对于这个简略的示例,它无需进一步批改即可工作。以下清单(来自<br/>src/main/java/com/example/batchprocessing/BatchProcessingApplication.java)显示了应用程序类:</p><p>package com.example.batchprocessing;</p><p>import org.springframework.boot.SpringApplication;</p><p>import org.springframework.boot.autoconfigure.SpringBootApplication;</p><p>@SpringBootApplication</p><p>public class BatchProcessingApplication {</p><p>public static void main(String[] args) throws Exception {</p><p>System.exit(SpringApplication.exit(SpringApplication.run(BatchProcessingApplication.class, args)));</p><p>}</p><p>}</p><p>@SpringBootApplication是一个不便的正文,它增加了以下所有内容:</p><p>@Configuration: 将类标记为应用程序上下文的 bean 定义源。<br/>@EnableAutoConfiguration:通知 Spring Boot 依据类门路设置、其余 bean 和各种属性设置开始增加 bean。例如,如果spring-webmvc位于类门路上,则此正文将应用程序标记为 Web 应用程序并激活要害行为,例如设置DispatcherServlet.<br/>@ComponentScan: 通知 Spring 在包中查找其余组件、配置和服务com/example,让它找到控制器。<br/>该main()办法应用 Spring Boot 的SpringApplication.run()办法来启动应用程序。您是否留神到没有一行 XML?也没有web.xml文件。这个 Web 应用程序是 100% 纯 Java,您不用解决任何管道或基础设施的配置。</p><p>请留神SpringApplication.exit()并System.exit()确保 JVM 在作业实现后退出。无关更多详细信息,请参阅Spring Boot 参考文档中的应用程序退出局部。</p><p>出于演示目标,有代码能够创立一个JdbcTemplate、查询数据库并打印出批处理作业插入的人员姓名。</p><p>构建一个可执行的 JAR<br/>您能够应用 Gradle 或 Maven 从命令行运行应用程序。您还能够构建一个蕴含所有必要依赖项、类和资源的单个可执行 JAR 文件并运行它。构建可执行 jar 能够在整个开发生命周期、跨不同环境等中轻松地作为应用程序交付、版本化和部署服务。</p><p>如果您应用 Gradle,则能够应用./gradlew bootRun. 或者,您能够应用构建 JAR 文件./gradlew build,而后运行 JAR 文件,如下所示:</p><p>java -jar build/libs/gs-batch-processing-0.1.0.jar<br/>如果您应用 Maven,则能够应用./mvnw spring-boot:run. 或者,您能够应用构建 JAR 文件,./mvnw clean package而后运行该 JAR 文件,如下所示:</p><p>java -jar 指标/gs-batch-processing-0.1.0.jar<br/>此处形容的步骤创立了一个可运行的 JAR。您还能够构建经典的 WAR 文件。</p><p>该作业为每个被转换的人打印一行。作业运行后,您还能够看到查询数据库的输入。它应该相似于以下输入:</p><p>Converting (firstName: Jill, lastName: Doe) into (firstName: JILL, lastName: DOE)</p><p>Converting (firstName: Joe, lastName: Doe) into (firstName: JOE, lastName: DOE)</p><p>Converting (firstName: Justin, lastName: Doe) into (firstName: JUSTIN, lastName: DOE)</p><p>Converting (firstName: Jane, lastName: Doe) into (firstName: JANE, lastName: DOE)</p><p>Converting (firstName: John, lastName: Doe) into (firstName: JOHN, lastName: DOE)</p><p>Found <firstName: JILL, lastName: DOE> in the database.</p><p>Found <firstName: JOE, lastName: DOE> in the database.</p><p>Found <firstName: JUSTIN, lastName: DOE> in the database.</p><p>Found <firstName: JANE, lastName: DOE> in the database.</p><p>Found <firstName: JOHN, lastName: DOE> in the database.</p><p>概括<br/>祝贺!您构建了一个批处理作业,该作业从电子表格中提取数据,对其进行解决,而后将其写入数据库。</p></article>