在春季批处理中使用分区步骤访问@JobScope bean [英] Access @JobScope bean in spring batch with partitioned step

查看:370
本文介绍了在春季批处理中使用分区步骤访问@JobScope bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以访问在分区步骤中定义为@JobScope的bean?

Is there a way to access bean which is defined as @JobScope in partitioned step?

我们将http客户端bean定义为@JobScope,因为它对于每个作业都是唯一的,但是是动态创建的,因此我们需要在从属步骤中使用它来发出发布请求.当我们对所有东西进行自动接线时,就会得到

We defined http client bean as @JobScope since it is unique per job but dynamically created and we need it in slave steps to issue post requests. When we autowire everything we get

Error creating bean with name 'scopedTarget.captureErpStockTasklet':
Scope 'step' is not active for the current thread; consider defining a 
scoped proxy for this bean if you intend to refer to it from a singleton;
nested exception is java.lang.IllegalStateException: No context holder 
available for step scope

这里是作业配置类(我删除了不需要的所有内容,只保留了分区步骤的配置和@JobScope中的Client类,因为在每次运行的作业中,它都必须是特定于作业的:

Here is job configuration class (I have removed everything not needed, left only configuration of partitioned step and Client class which is in @JobScope because on every job run it needs to be job specific:

@Configuration
@EnableBatchProcessing
@ComponentScan(basePackages = {"com.example.importjob"})
public class FrozenFileImportJobConfig {
@Value("${thread.pool:10}")
private int threadPoolSize;
@Value("${partitioner.max.thread.pool:10}")
private int maxThreadPoolSize;
@Value("${grid.size:10}")
private int gridSize;
@Value("${client.url:some_url}")
private int url;
@Value("${client.id:client_id}")
private int clientId;
@Value("${client.secret:secret}")
private int clientSecret;
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
 @Autowired
private ErpStockIdPartitioner erpStockIdPartitioner;
@Autowired
private CaptureErpStockTasklet captureErpStockTasklet;
@Bean(destroyMethod = "destroy")
@JobScope
public Client client() {
  return new Client(url, clientId, clientSecret);
}

public ExecutionContextPromotionListener contextPromotionListener() {
  final ExecutionContextPromotionListener executionContextPromotionListener = new ExecutionContextPromotionListener();
  executionContextPromotionListener.setKeys(new String[] {"erp_stock_ids"});
  return executionContextPromotionListener;
}

public Step captureErpStockDBTaskletStep() {
  return stepBuilderFactory.get("captureErpStockDBTaskletStep").tasklet(captureErpStockTasklet).build();
}

@Bean
public ThreadPoolTaskExecutor erpStockIdTaskExecutor() {
  final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
  threadPoolTaskExecutor.setCorePoolSize(threadPoolSize);
  threadPoolTaskExecutor.setMaxPoolSize(maxThreadPoolSize);
  threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
  return threadPoolTaskExecutor;
}
public Step partitioningCaptureStep() {
  return stepBuilderFactory.get("partitioningCaptureStep").partitioner(captureErpStockDBTaskletStep())
.partitioner("erpStockIdPartitioner", erpStockIdPartitioner).taskExecutor(erpStockIdTaskExecutor())
.gridSize(gridSize).allowStartIfComplete(true).build();
}
@Bean
public Job riverIslandFrozenFileImportJob() {
  return jobBuilderFactory.get("riverIslandFrozenFileImportJob").start(partitioningCaptureStep()).build();
}
}

这是captureErpStockDBTasklet,它是从主控partitioningCaptureStep作为分区步骤调用的:

And here is captureErpStockDBTasklet which is invoked as partitioned step from master partitioningCaptureStep:

@Component
@StepScope
public class CaptureErpStockTasklet implements Tasklet {
  private static final Logger LOG = LoggerFactory.getLogger(CaptureErpStockTasklet.class);
  @Value("#{jobParameters[" + FtpJobParameters.ORGANIZATION_ID + "]}")
  private Long organizationId;
  @Autowired
  private ErpStockRepository erpStockRepository;
  @Autowired
  private Client client;
  @Override
  public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) throws Exception {
    //importing of erp stock from DB, nothing special in that code so removed
     client.captureErpStock(stock);
     LOG.info("[{}] Finished importing ERP {}", organizationId, erpStock);
     return RepeatStatus.FINISHED;
  }
}

当我将配置Clinet更改为@StepScope时,它可以很好地工作,但是,我要为不是我想要的每一步创建客户端,所以我想为整个工作准备一个.

When I change in configuration Clinet to be @StepScope it works fine but than I get client created for every step which is not what I want, I want to have one for entire job.

推荐答案

我认为在分区步骤中使用Job Scope Bean时,这在spring batch中是一个问题.

I think that this is an issue in spring batch when useing Job Scope beans in a partitioned step.

请参阅: https://jira.spring.io/browse/BATCH-2269对作业范围bean进行多线程访问在Spring Batch 3.0中

这篇关于在春季批处理中使用分区步骤访问@JobScope bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆