【问题标题】:spring batch before step not getting called, need step execution context未调用步骤之前的弹簧批处理,需要步骤执行上下文
【发布时间】:2021-04-13 12:11:56
【问题描述】:

在我的春季批处理工作流配置中,我的项目编写器如下:

@Bean
@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
public ItemWriter<Price> skippedItemWriter(@Value("#{stepExecution.executionContext}") ExecutionContext executionContext) {
    return new SkippedItemWriter(executionContext);
}


public class SkippedItemWriter implements ItemWriter<Price>, StepExecutionListener {

    private static final Logger LOGGER = getLogger(SkippedItemWriter.class);

    private final ExecutionContext executionContext;
    private StepExecution stepExecution;

    public SkippedItemWriter(final ExecutionContext executionContext) {
        this.executionContext = executionContext;
    }

    @Override
    public void write(List<? extends Price> items) {

        if (CollectionUtils.isEmpty(items)) {
            return;
        }
        /blah 
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {
        LOGGER.info("in beforeStep");
        this.stepExecution = stepExecution;
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return null;
    }
}

我的前一步和后一步没有被调用。

bean 必须是步骤范围的。

我正在尝试获取我在前面步骤中设置的发布计数:

ExecutionContext context = stepContribution.getStepExecution().getJobExecution().getExecutionContext();
context.putInt((PUBLISH_COUNT.name()), 0);

我已尝试返回 SkippedItemWriter() 而不是 ItemWriter&lt;T&gt;,但我收到另一个代理错误。

我应该添加 SkippedItemWriter 是复合编写器的一部分:

@Bean
@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
public ItemWriter<Price> compositeWriter() {
    CompositeItemWriter<Price> itemWriter = new CompositeItemWriter<>();
itemWriter.setDelegates(Arrays.asList(
              skippedItemWriter(null)));

        return itemWriter;   }

【问题讨论】:

  • 您需要将返回类型更改为 SkippedItemWriter 否则 Spring 不会将其检测为 StepExecutionListener
  • 我试过了,但没用。我应该添加这个特定的编写器是作为返回 ItemWriter 的复合编写器的一部分的委托
  • 那么您需要手动将其注册为您的步骤的侦听器,除非该委托也是可以委托给其编写者的StepExecutionListener
  • 你能举个例子吗?我的作家实现了 StepExecutionListener。我已经添加了一个侦听器... .listener(promoteContextListener()) with keys
  • 您的编写者实现了组合没有实现,而组合是该步骤看到的而不是您自己的实现。因此,您需要手动将您的 skippedItemWriter 注册为您的步骤的侦听器。

标签: java spring spring-batch


【解决方案1】:

原因是因为您的SkippedItemWriter 是复合项目编写器的代表,它不会自动注册为侦听器,这应该手动完成。以下是文档Intercepting Step Execution 部分的摘录:

If the listener is nested inside another component, it needs to be explicitly
registered (as described previously under "Registering ItemStream with a Step").

因此,您需要在您的步骤中将SkippedItemWriter 显式注册为侦听器。

【讨论】:

  • 您的步骤中可以有多个听众吗?我已经通过了一个 executionpromotionlistener。其次,如果 SkippedItemWriter 的构造函数带参数,是否可以将 null 作为 Args 传递?
  • 是的,您可以有多个听众。 StepBuilder#listener 方法将侦听器添加到列表中。为什么需要通过null?在您的示例中,您不需要将ExecutionContext 作为参数传递给SkippedItemWriter 的构造函数,您可以从StepExecution 字段中获取执行上下文。
  • 我的步骤添加了如下监听器:.writer(compositeWriter()).listener(promoteContextListener()).listener(new SkippedItemWriter(dep1, dep2)) 但是skippedItemWriter 有两个构造函数参数(dep1,dep2),我并不想在这里实例化并传递。
  • 这与这里的问题有什么关系?您有一个 bean,您希望将其注册为步进侦听器,以便按预期调用其 beforeStepafterStep 方法。在您的情况下,此问题的答案是在步骤中手动将此 bean 注册为侦听器。现在这个 bean 的依赖项是如何注入的则是另一回事了。我可以告诉您的是,不需要使用 SpEL 注入执行上下文并将其传递给构造函数,因为您可以从通过 beforeStep 注入编写器的 StepExecution 实例获取执行上下文。
  • 如果您有其他依赖项,您需要找到一种方法将它们注入到您的 bean 中,无论是手动还是通过 Spring DI 机制。但同样,这是另一个问题。
猜你喜欢
  • 2015-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多