当前位置: 首页 > 知识库问答 >
问题:

SPRING-BATCH错误:没有可用于步骤范围的上下文持有者

桓宜
2023-03-14

这是我的简单工作配置:

@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;
        }

}

如您所见,我已按照此处的说明配置了stepScopebean,并将以下行添加到我的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/Hibrate:

@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批处理JDBC作业存储库:

@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。

出什么事了?

谢谢。

共有2个答案

曾山
2023-03-14

使用Java配置,您不需要为自己注册StepScope(这是用于XML的),在配置上添加注释@EnableBatchProcess。在您的情况下,您不需要添加@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。

柳均
2023-03-14

我的错。

@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();
    }
    
    
}

请注意,helloWorldTaskletbean声明为@StepScope而不是my@Step

 类似资料:
  • 我试图在运行时设置spring批处理作业的块大小,方法是将其注入我的步骤中,如下所示: 但我得到以下错误:java.lang.非法状态异常:没有上下文持有人可用的工作范围 我在网上做了一些研究,但不明白为什么我会遇到这个异常。如果您能帮助我理解这个错误的含义以及如何解决它,我将不胜感激。谢谢!

  • 我试图在Spring批处理作业中使用多线程步骤,但我得到一个“范围‘作业’对于当前线程不活动……”。我在Spring中尝试了几种方法,但目前我正在使用我认为是OOTB Spring构造的方法,但仍然失败。 错误是: 基本作业结构简化:作业SoftLayerUpload作业步骤:softlayerUploadFileStep(不能多线程)从Excel文件读取写入SoftLayerDataItemQu

  • 我正在开发一个Spring批处理作业,它使用MultiResourcePartitioner并行处理多个输入文件。在ItemProcessor中,我需要获取当前输入文件中的记录数。我从步骤上下文中获取当前文件名,并读取文件中的行数: 这一切似乎工作,但我得到例外时,从处理器线程访问步骤上下文: 有没有办法从分区作业的处理器获取当前输入文件名? 下面是相关配置:

  • 我可以在xml配置中使用而没有任何问题,但如果将其用作如下注释。它会抛出以下错误 原因:组织。springframework。豆。工厂UnsatisfiedDependencyException:创建在类路径资源[BatchConfiguration.class]中定义的名为“step1”的bean时出错:通过索引1为[org.springframework.batch.item.ItemRead

  • 围绕这个主题似乎有很多问题,但我似乎找不到答案。如果这是个骗局,对不起! 我有一个有许多步骤的工作…在某一点上,我想并行地运行多个文件的项处理(读/验证/写)。在使这段代码并行之前,我同步运行了它,一切都很好。当我使用task-executor添加batch:split时,我现在得到的错误是: 2020-09-01 01:07:12,668[SimpleAsyncTaskExecutor-1]错误

  • 问题内容: 事务范围的持久性上下文和扩展的持久性上下文之间有什么区别? 问题答案: 在JSR-220 Enterprise JavaBeans 3.0规范中清楚地解释了差异: 5.6容器管理的持久性上下文 (…) 可以将容器管理的持久性上下文定义为具有范围为单个事务的生存期或跨越多个事务的扩展生存期,这取决于创建容器时所指定的生存期 。该规范分别将这种持久性上下文称为 事务范围的持久性上下文 和