英文:
SPRING-BATCH ERROR: No context holder available for step scope
问题
这是我的简单作业配置:
@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;
}
}
正如您所看到的,我已经按照这里的说明配置了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
...
请注意,我的项目配置了两个数据源,还有Spring MVC Web:
数据源 1,用于 JPA/Hibernate:
@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();
}
}
数据源 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);
}
}
我找不到这里提到的神秘XML。
出了什么问题?
谢谢。
英文:
This is my simple job configuration:
@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;
}
}
As you can see I have configured the stepScope
bean as instructed over here and and also added the following line to my application.properties
:
spring.main.allow-bean-definition-overriding=true
This is the error I am getting. Where am I going wrong ?
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
Please note my project has 2 datasources configured, along with Spring MVC Web:
Datasource 1, for 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, for 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);
}
}
I am unable to find the mysterious XML mentioned over here.
What is going wrong ?
Thanks.
答案1
得分: 3
我的错误。
@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
。
英文:
My mistake.
@StepScope
should be declared like the following:
@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();
}
}
Notice that the helloWorldTasklet
bean is declared as @StepScope
and not my @Step
.
答案2
得分: 0
使用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注解。
英文:
Using Java configuration, you don't need to register yourself the StepScope (this is for XML), add the annotation @EnableBatchProcessing on your configuration. In your case, you don't need to add @StepScope and @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();
}
}
Use @JobScope and @StepScope on bean used in your step or job when you need a new instance for each job or step.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论