【问题标题】:Accesing JobContext from a partitioned step in JSR 352从 JSR 352 中的分区步骤访问作业上下文
【发布时间】:2014-04-13 21:53:48
【问题描述】:

我正在尝试在批处理之间传递对象,但在尝试从分区步骤(批处理)访问 jobContext 时遇到问题。

根据 JSR 352 规范

9.4.1.1 批处理上下文生命周期和范围: 批处理上下文具有线程亲和性,并且仅对批处理可见 在该特定线程上执行的工件。注入批处理上下文 超出范围时,字段可能为空。每种上下文类型都有不同的 范围和生命周期如下: 1.作业上下文 每个作业执行都有一个 JobContext。它为一个人的一生而存在 工作。 并行的每个子线程都有一个不同的 JobContext 执行(例如分区步骤)。 2. StepContext 每个步骤执行都有一个 StepContext。它终生存在 步骤。对于分区步骤,有一个 StepContext 用于 父步骤/线程;每个子线程都有一个不同的 StepContext。

我的(失败的)解决方案是使用 JobContext.setTransientUserData,但由于分区步骤使用不同的 JobContext,我无法获取 TransientUserData。

除了我正在尝试做的事情之外,还有其他选择吗?使用 PartitionMapper 属性是不可能的,因为我需要向每个分区传递一个对象,而不是一个字符串。

说清楚,我需要这样做:

  1. NormalBatchlet -> 保存要在下一步中使用的对象。
  2. PartitionedBatchlet -> 获取上一步中保存的对象。此对象不是简单的字符串,因此使用 PartitionMapper 属性不是解决方案。

更新

我现在使用带有 HashMap 的简单单例 EJB 来存储步骤之间的对象,当作业完成时,我清除此映射以避免资源泄漏。

这是一种解决方法,因为我真的只想使用 javax.batch 包而不依赖于 EJB,所以我不把它作为答案。

【问题讨论】:

  • 不知道它在 JSR 中是如何定义的,但是在 Spring Batch 中你可以从StepContextStepContext 可以注入到 step scoped bean 中,也可以从 StepSynchronizationManager 访问它。
  • 遗憾的是,我在 glassfish 4 中使用 JSR 352,而不是 spring batch
  • 在 JBoss 7 / WildFly 中,所有分区都将看到相同的 JobContext 对象,并且每个分区都有一个单独的 StepContext。

标签: java batch-processing glassfish-4


【解决方案1】:

在规范中提到了访问上下文的唯一一种方法 - 注入。请参阅第 9.4.1 段。

"9.4.1 批处理上下文

通过使用标准@Inject 注解 (javax.inject.Inject) 的注入来访问批处理上下文。注入批处理上下文的字段不能是静态的,也不能是最终的。

例如:

@Inject JobContext _jctxt;

@Inject StepContext _sctxt;

批处理运行时负责确保根据当前执行的作业或步骤注入正确的上下文对象。”

【讨论】:

【解决方案2】:

你可以尝试这样的东西,它应该符合当前规范的编程模型。

使用 NormalBatchlet 中的持久步骤数据存储第一步中的对象:

stepCtx.setPersistentUserData(mySerializableData);

通过查找上一步从分区中的第一步检索数据:

Long execId = jobCtx.getExecutionId();

List<StepExecution> stepExecs = jobOperator.getStepExecutions(execID);

MyPersistentUserData myData;

for (StepExecution step : stepExecs) {
    if (step.getStepName().equals("somePreviousStepX") {
        myData = (MyPersistentUserData)step.getPersistentUserData();
    }
}

//use myData

【讨论】:

  • 非常不错的 hack。希望我们不必这样做。似乎无法通过无法获取父作业瞬态数据来解决巨大的差距。我还假设我们将完全无法在其中设置任何工作瞬态数据,因为对象是完全独立的。
  • 相同的解决方案,使用流而不是 for 循环:myData = (MyPersistentUserData) stepExecs.stream().filter(step -&gt; step.getStepName().equals("somePreviousStepX")).findFirst().orElse(null);
【解决方案3】:

没有规范定义的方式来在主线程的 JobContext 和分区级别的 JobContext(s) 之间共享临时用户数据。这是一个可以理解的混淆点,但这确实是预期的设计。

【讨论】:

  • 但是,根据规范:9.5.3 PartitionCollector 接口 分区收集器提供了一种将数据从各个分区发送到在父线程上运行的单个控制点的方法。 PartitionAnalyzer 用于接收和处理这些数据。 这不是我正在尝试的相反吗?我需要将一个对象从 step1(普通 batchlet)传递到 step2(分区 batchlet)
  • 我会编辑这个问题,因为在阅读后还不清楚这一点:-P 感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多