【问题标题】:Spring Batch @JobScope bean creation error "A bean with that name has already been defined"Spring Batch @JobScope bean 创建错误“已定义具有该名称的 bean”
【发布时间】:2021-01-28 04:22:21
【问题描述】:

在我的 Spring 批处理项目(Spring Boot 版本 2.3.4.RELEASE,Java 1.8)中,我有一个处理器组件需要访问作业 ID(用于跟踪目的)。我在 bean 声明中添加了 @JobScope,这允许我访问 Job Id。

@Component("dealerItemProcessor")
@JobScope
public class DealerItemProcessor implements ItemProcessor<Dealer, Dealer> {    
   @Value("#{jobExecution}")
   private JobExecution jobExecution;
    
   @Override
   public Dealer process(final Dealer dealer) throws Exception {
      //Get jobExecution.getJobId(), process data bean
   }

我这样在 XML 中声明了 Job:

<job id="syncJob" >
    <step id="step1">
        <tasklet>
            <chunk reader="itemReader"
                   processor="dealerItemProcessor"
                   writer="itemWriter" commit-interval="1"/>
        </tasklet>
    </step>
    <listeners>
        <listener ref="syncJobCompletionNotificationListener"/>
    </listeners>
</job>

XML 配置加载为:

@Configuration
@EnableAutoConfiguration
@ImportResource("classpath:batch-job.xml")
public class XMLConfigurationLoader {
}

作业是这样安排的:

public SyncJobScheduler(@Qualifier("syncJob") Job dealerSyncJob,
                              JobLauncher jobLauncher) {
    this.syncJob = syncJob;
    this.jobLauncher = jobLauncher;
}
@Scheduled(cron = "0 0 */1 * * *")
public void schedule() throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
   jobLauncher.run(syncJob, new JobParametersBuilder()
                .addDate("date", new Date())
                .toJobParameters());
}

当我在 Linux 操作系统服务器和 OpenJDK 1.8 中构建和运行项目时,我收到以下错误。

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'scopedTarget.dealerItemProcessor', defined in BeanDefinition defined in URL [jar:file:/var/www/jobs/upload-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/sync/connect/processor/DealerItemProcessor.class], could not be registered. A bean with that name has already been defined in URL [jar:file:/var/www/jobs/upload-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/sync/connect/processor/DealerItemProcessor.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

我已启用调试模式并看到相同的错误。我该如何解决这个问题?可以指点一下吗?

更新 1: 我尝试将 JobScope 更改为 StepScope,并看到类似的异常。 2020-10-15 10:53:02.651 [调试] [主要]

[org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter:37] Application failed to start due to an exception
org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'scopedTarget.dealerItemProcessor' defined in BeanDefinition defined in URL [jar:file:/var/www/jobs/upload-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/sync/connect/processor/DealerItemProcessor.class]: Cannot register bean definition [Root bean: class [org.springframework.aop.scope.ScopedProxyFactoryBean]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in BeanDefinition defined in URL [jar:file:/var/www/jobs/upload-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/sync/connect/processor/DealerItemProcessor.class]] for bean 'scopedTarget.dealerItemProcessor': There is already [Generic bean: class [com.sync.connect.processor.DealerItemProcessor]; scope=step; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file:/var/www/jobs/upload-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/sync/connect/processor/DealerItemProcessor.class]] bound.

【问题讨论】:

  • 你能不能试试@StepScope 而不是@JobScope。能否请您告诉我为什么您需要 @JobScope 这个组件。
  • @SujayMohan 使用@JobScope 我得到了类似的错误。
  • @SujayMohan 我需要一个唯一标识符来标记/跟踪在每次运行作业期间处理的数据。
  • 我希望你需要@JobScope 来获取jobExecution 和getId 对吗?
  • SpringBoot 正在创建dealerItemProcessor bean 的两个实例。它在组件扫描期间创建第一个,在处理作业生命周期 bean 时创建第二个。默认行为是在创建第二个 bean 时抛出错误。您可以通过将 spring.main.allow-bean-definition-overriding=true 添加到您的 application.properties 来覆盖此行为。另外,我可以通过将 @EnableAutoConfiguration 替换为 @EnableBatchProcessing 来让您的示例正常工作。

标签: java spring spring-boot spring-batch


【解决方案1】:

您可以使用@StepScope 代替@JobScope。您可以使用stepExecution.getJobExecution() 来获取jobExecution。然后你提到你可以得到jobId。

【讨论】:

    【解决方案2】:

    我通过实现 StepExecutionListener 来实现这一点。这提供了对 StepExecution 对象的访问权限,我们可以从中获取 Job Id。

    @Component("dealerItemProcessor")
    public class DealerItemProcessor implements ItemProcessor<Dealer, Dealer> , StepExecutionListener {
        
        private StepExecution stepExecution;
    
        @Override
        public Dealer process(final Dealer dealer) throws Exception {
        //get unique JobId like this - stepExecution.getJobExecutionId()
        // process logic
        }
    
        @Override
        public void beforeStep(StepExecution stepExecution) {
            //get the stepExecution Object.
            this.stepExecution = stepExecution;
        }
    
        @Override
        public ExitStatus afterStep(StepExecution stepExecution) {
            return null;
        }
    }
    

    此解决方案通过提供备用解决方案来解决获取 JobId 的需要。它没有解决问题中发布的 Bean 创建异常。

    【讨论】:

      猜你喜欢
      • 2023-01-10
      • 1970-01-01
      • 1970-01-01
      • 2018-08-11
      • 2012-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-09-27
      相关资源
      最近更新 更多