Spring Retry 可以与 Spring Batch FlatFileItemReader 一起使用吗
Can Spring Retry be used with Spring Batch FlatFileItemReader
我有以下 ItemReader
:
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
public class MyReader extends FlatFileItemReader<Holding> {
@Autowired
public MyReader(LineMapper<Holding> lineMapper, File loadFile) {
setResource(new FileSystemResource(loadFile));
final int NUMBER_OF_HEADER_LINES = 1;
setLinesToSkip(NUMBER_OF_HEADER_LINES);
setLineMapper(lineMapper);
}
@Override
@Retryable(value=ItemStreamException.class, maxAttempts=5, backoff=@Backoff(delay=1800000))
public void open(ExecutionContext executionContext) throws ItemStreamException {
super.open(executionContext);
}
}
要读取的文件(即 loadFile
)在 运行 作业时可能可用,也可能不可用。如果文件不可用,我希望 reader 休眠 ~30 分钟,然后重试打开文件。如果在五次尝试后仍未找到该文件,它可能会像往常一样通过抛出 ItemStreamException
来失败。
不幸的是,上面的代码没有尝试重试打开文件。它在第一次调用打开时抛出 ItemStreamException
并且不会重试打开。
有人可以解释一下如何做到这一点吗?注意:我在 SpringBootApplication
class.
上确实有 @EnableRetry
这个有效。我做了一些小改动,因为我不知道你的 类.
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath(
"org.springframework.boot:spring-boot-gradle-plugin:1.4.0.RELEASE",
)
}
}
apply plugin: 'java'
apply plugin: 'spring-boot'
tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
repositories {
mavenCentral()
}
springBoot {
mainClass = "test.MyReader"
}
dependencies {
compile(
'org.springframework.boot:spring-boot-starter',
'org.springframework.boot:spring-boot-starter-aop',
'org.springframework.retry:spring-retry',
)
}
MyApplication.java
@EnableRetry
@SpringBootApplication
public class MyApplication implements CommandLineRunner {
private final MyReader myReader;
@Autowired
public MyApplication(MyReader myReader) {
this.myReader = myReader;
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
myReader.read();
}
}
MyReader.java
@Service
public class MyReader {
private static final String PATH = "a2";
private final Logger logger = LoggerFactory.getLogger(MyReader.class);
public MyReader() {
}
@Retryable(value = IOException.class, maxAttempts = 5, backoff = @Backoff(delay = 5000))
public void read() throws IOException {
final Resource resource = new FileSystemResource(PATH);
logger.info("\n\nRead attempt: {}\n", resource);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
final String content = reader.lines().collect(Collectors.joining(" "));
logger.info("\n\nFile content: {}\n", content);
}
}
}
当您执行文件时,您会在日志中看到一条 "Read attempt" 消息和一条 "File content" 消息。我什至在其中添加了空行,因此现在很难忽略。
当文件不存在时,您将看到五个 "Read attempt" 消息,然后抛出异常。
我将重试时间更改为 5 秒。如果你足够快,你可以在没有文件的情况下开始,然后在那里制作一些文件,你会看到它有效。您应该看到几次读取尝试,最后看到文件内容。
我看到您已经为这个问题苦苦挣扎了几天。请不要提出不必要的问题,因为它们对社区没有帮助。为了将来的参考,尽量坚持你的一个问题,如果需要修改它。
从 Spring 引导版本 1.3.1.RELEASE 移动到 1.4.0.RELEASE(及其相应的自动版本化依赖项,例如 spring-boot-starter-batch
)解决了该问题。重试在 1.4.0.RELEASE 中工作,如 OP 中所实现的那样。在 1.3.1.RELEASE 中不起作用。这是现在正在使用的 gradle 文件:
buildscript {
ext {
// Previously using 1.3.1.RELEASE where retry functionality does not work
springBootVersion = '1.4.0.RELEASE'
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
configurations {
provided
}
sourceSets {
main {
compileClasspath += configurations.provided
}
}
jar {
baseName = 'load'
version = '1.0'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-batch')
compile('org.springframework.boot:spring-boot-configuration-processor')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-mail')
compile('org.springframework.boot:spring-boot-starter-aop')
compile('org.projectlombok:lombok:1.16.6')
compile('org.hibernate:hibernate-validator:5.2.4.Final')
compile('org.quartz-scheduler:quartz:2.2.3')
runtime('javax.el:javax.el-api:2.2.4')
runtime('org.glassfish.web:javax.el:2.2.4')
runtime('net.sourceforge.jtds:jtds:1.3.1')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.batch:spring-batch-test')
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.11'
}
注意:考虑使用 JobExecutionDecider
重试使用 FlatFileItemReader
的步骤。但是,ItemStreamException
会导致整个作业和应用程序在决策者没有机会执行的情况下终止。
我有以下 ItemReader
:
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
public class MyReader extends FlatFileItemReader<Holding> {
@Autowired
public MyReader(LineMapper<Holding> lineMapper, File loadFile) {
setResource(new FileSystemResource(loadFile));
final int NUMBER_OF_HEADER_LINES = 1;
setLinesToSkip(NUMBER_OF_HEADER_LINES);
setLineMapper(lineMapper);
}
@Override
@Retryable(value=ItemStreamException.class, maxAttempts=5, backoff=@Backoff(delay=1800000))
public void open(ExecutionContext executionContext) throws ItemStreamException {
super.open(executionContext);
}
}
要读取的文件(即 loadFile
)在 运行 作业时可能可用,也可能不可用。如果文件不可用,我希望 reader 休眠 ~30 分钟,然后重试打开文件。如果在五次尝试后仍未找到该文件,它可能会像往常一样通过抛出 ItemStreamException
来失败。
不幸的是,上面的代码没有尝试重试打开文件。它在第一次调用打开时抛出 ItemStreamException
并且不会重试打开。
有人可以解释一下如何做到这一点吗?注意:我在 SpringBootApplication
class.
@EnableRetry
这个有效。我做了一些小改动,因为我不知道你的 类.
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath(
"org.springframework.boot:spring-boot-gradle-plugin:1.4.0.RELEASE",
)
}
}
apply plugin: 'java'
apply plugin: 'spring-boot'
tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
repositories {
mavenCentral()
}
springBoot {
mainClass = "test.MyReader"
}
dependencies {
compile(
'org.springframework.boot:spring-boot-starter',
'org.springframework.boot:spring-boot-starter-aop',
'org.springframework.retry:spring-retry',
)
}
MyApplication.java
@EnableRetry
@SpringBootApplication
public class MyApplication implements CommandLineRunner {
private final MyReader myReader;
@Autowired
public MyApplication(MyReader myReader) {
this.myReader = myReader;
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
myReader.read();
}
}
MyReader.java
@Service
public class MyReader {
private static final String PATH = "a2";
private final Logger logger = LoggerFactory.getLogger(MyReader.class);
public MyReader() {
}
@Retryable(value = IOException.class, maxAttempts = 5, backoff = @Backoff(delay = 5000))
public void read() throws IOException {
final Resource resource = new FileSystemResource(PATH);
logger.info("\n\nRead attempt: {}\n", resource);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
final String content = reader.lines().collect(Collectors.joining(" "));
logger.info("\n\nFile content: {}\n", content);
}
}
}
当您执行文件时,您会在日志中看到一条 "Read attempt" 消息和一条 "File content" 消息。我什至在其中添加了空行,因此现在很难忽略。
当文件不存在时,您将看到五个 "Read attempt" 消息,然后抛出异常。
我将重试时间更改为 5 秒。如果你足够快,你可以在没有文件的情况下开始,然后在那里制作一些文件,你会看到它有效。您应该看到几次读取尝试,最后看到文件内容。
我看到您已经为这个问题苦苦挣扎了几天。请不要提出不必要的问题,因为它们对社区没有帮助。为了将来的参考,尽量坚持你的一个问题,如果需要修改它。
从 Spring 引导版本 1.3.1.RELEASE 移动到 1.4.0.RELEASE(及其相应的自动版本化依赖项,例如 spring-boot-starter-batch
)解决了该问题。重试在 1.4.0.RELEASE 中工作,如 OP 中所实现的那样。在 1.3.1.RELEASE 中不起作用。这是现在正在使用的 gradle 文件:
buildscript {
ext {
// Previously using 1.3.1.RELEASE where retry functionality does not work
springBootVersion = '1.4.0.RELEASE'
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
configurations {
provided
}
sourceSets {
main {
compileClasspath += configurations.provided
}
}
jar {
baseName = 'load'
version = '1.0'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-batch')
compile('org.springframework.boot:spring-boot-configuration-processor')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-mail')
compile('org.springframework.boot:spring-boot-starter-aop')
compile('org.projectlombok:lombok:1.16.6')
compile('org.hibernate:hibernate-validator:5.2.4.Final')
compile('org.quartz-scheduler:quartz:2.2.3')
runtime('javax.el:javax.el-api:2.2.4')
runtime('org.glassfish.web:javax.el:2.2.4')
runtime('net.sourceforge.jtds:jtds:1.3.1')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.batch:spring-batch-test')
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.11'
}
注意:考虑使用 JobExecutionDecider
重试使用 FlatFileItemReader
的步骤。但是,ItemStreamException
会导致整个作业和应用程序在决策者没有机会执行的情况下终止。