SPRING-BATCH 错误:没有可用于步骤范围的上下文持有者
Posted
技术标签:
【中文标题】SPRING-BATCH 错误:没有可用于步骤范围的上下文持有者【英文标题】:SPRING-BATCH ERROR: No context holder available for step scope 【发布时间】:2020-11-29 11:13:58 【问题描述】:这是我的简单作业配置:
@Configuration
public class Testjob
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Bean
@org.springframework.batch.core.configuration.annotation.StepScope
public Step step1()
return stepBuilderFactory.get("step1")
.tasklet((stepContribution, chunkContext) ->
System.out.println("Hello World !");
return RepeatStatus.FINISHED;
).build();
@Bean
@DependsOn("step1")
public Job job1()
return jobBuilderFactory.get("job1")
.start(step1())
.build();
@Bean
public StepScope stepScope()
StepScope stepScope = new StepScope();
stepScope.setAutoProxy(true);
return stepScope;
如您所见,我已经按照here 的指示配置了stepScope
bean,并且还在我的application.properties
中添加了以下行:
spring.main.allow-bean-definition-overriding=true
这是我得到的错误。 我哪里出错了?
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.step1': 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
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:368) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:192) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at com.sun.proxy.$Proxy359.getName(Unknown Source) ~[na:na]
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:115) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:410) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:319) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:147) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at com.sun.proxy.$Proxy360.run(Unknown Source) ~[na:na]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:192) ~[spring-boot-autoconfigure-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeLocalJobs(JobLauncherCommandLineRunner.java:166) ~[spring-boot-autoconfigure-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:153) ~[spring-boot-autoconfigure-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:148) ~[spring-boot-autoconfigure-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:784) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:768) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at com.foo.BatchApplication.main(BatchApplication.java:17) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.2.6.RELEASE.jar:2.2.6.RELEASE]
Caused by: java.lang.IllegalStateException: No context holder available for step scope
at org.springframework.batch.core.scope.StepScope.getContext(StepScope.java:167) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.batch.core.scope.StepScope.get(StepScope.java:99) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:356) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
... 37 common frames omitted
请注意,我的项目配置了 2 个数据源以及 Spring MVC Web:
数据源 1,用于 JPA/Hiberate:
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory",
basePackages = "com.foo.repositories")
public class JpaConfig
@Autowired
private Environment env;
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSourceProperties dataSourceProperties()
return new DataSourceProperties();
@Bean
@Primary
@DependsOn("dataSourceProperties")
public DataSource hikariDataSource(DataSourceProperties dataSourceProperties)
return dataSourceProperties.initializeDataSourceBuilder().build();
@Bean("entityManagerFactory")
@DependsOn("hikariDataSource")
public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean(EntityManagerFactoryBuilder
entityManagerFactoryBuilder, @Qualifier("hikariDataSource") DataSource dataSource)
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", env.getProperty("spring.hib.properties.hibernate.dialect"));
properties.put("hibernate.temp.use_jdbc_metadata_defaults", env.getProperty(
"spring.hib.properties.hibernate.temp.use_jdbc_metadata_defaults"));
return entityManagerFactoryBuilder.dataSource(dataSource)
.persistenceUnit("TestPersistenceUnit")
.properties(properties)
.packages("com.foo.entities")
.build();
DataSource 2,用于 Spring Batch JDBC Job Repository:
@Configuration
public class BatchFrameworkConfig
@Autowired
private Environment env;
@Bean("batch_datasource_properties")
@ConfigurationProperties("spring.batch.datasource")
public DataSourceProperties dataSourceProperties()
return new DataSourceProperties();
@Bean("batch_datasource")
@DependsOn("batch_datasource_properties")
public DataSource batchFrameworkDatasource(DataSourceProperties dataSourceProperties)
return dataSourceProperties.initializeDataSourceBuilder().build();
@Bean
@DependsOn("batch_datasource")
public BatchConfigurer defaultBatchConfigurer(@Qualifier("batch_datasource") DataSource dataSource)
return new DefaultBatchConfigurer(dataSource);
我无法找到here 中提到的神秘 XML。
出了什么问题?
谢谢。
【问题讨论】:
年份是 2020,SpringXMLConfiguration 被称为 mysterious XML :) 这只是配置 bean 的另一种方式,只需在 @987654330 的代码中定义具有相同 id 的 bean @文件。 @JAsgarov 我做到了。我定义了StepScope
bean。在我的工作配置中。这不正确吗?
@JAsgarov 我不明白你指的是什么。
@JAsgarov 什么 bean id ??
【参考方案1】:
使用Java配置,你不需要自己注册StepScope(这是针对XML的),在你的配置上添加注解@EnableBatchProcessing。在您的情况下,您不需要添加@StepScope 和@DependsOn。
@Configuration
@EnableBatchProcessing
public class Testjob
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Bean
public Step step1()
return stepBuilderFactory.get("step1")
.tasklet((stepContribution, chunkContext) ->
System.out.println("Hello World !");
return RepeatStatus.FINISHED;
).build();
@Bean
public Job job1()
return jobBuilderFactory.get("job1")
.start(step1())
.build();
当您需要每个作业或步骤的新实例时,在步骤或作业中使用的 bean 上使用 @JobScope 和 @StepScope。
【讨论】:
我需要 StepScope。我想知道如何配置它。是的,对于这项工作,我本身不需要 StepScope,但对于其他更复杂的工作,我需要它。 问题是为什么 StepScope 在这里不起作用,而不是不需要它。 谢谢,但这是我的错误。发布了正确的答案。 很高兴听到您解决问题。是的,您需要在步骤中使用 bean 来初始化上下文。【参考方案2】:我的错。
@StepScope
应声明如下:
@Configuration
@EnableBatchProcessing
public class Testjob
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Bean
@StepScope
public Tasklet helloWorldTasklet()
return (stepContribution, chunkContext) ->
System.out.println("Hello World !");
return RepeatStatus.FINISHED;
;
@Bean
public Step step1()
return stepBuilderFactory.get("step1")
.tasklet(helloWorldTasklet())
.build();
@Bean
public Job job1()
return jobBuilderFactory.get("job1")
.start(step1())
.build();
注意 helloWorldTasklet
bean 被声明为 @StepScope
而不是我的 @Step
。
【讨论】:
以上是关于SPRING-BATCH 错误:没有可用于步骤范围的上下文持有者的主要内容,如果未能解决你的问题,请参考以下文章
spring batch ftp 集成超时错误 - 使用 spring-boot/spring-batch 进行 ETL
Spring Batch 中没有可用于作业范围的上下文持有者