在春季批处理中使用分区步骤访问@JobScope bean [英] Access @JobScope bean in spring batch with partitioned step
问题描述
是否有一种方法可以访问在分区步骤中定义为@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屋!