英文:
Spring Batch @JobScope bean creation error "A bean with that name has already been defined"
问题
在我的Spring批处理项目中(Spring Boot版本为2.3.4.RELEASE,Java 1.8),我有一个处理器组件需要访问作业ID(用于跟踪目的)。我在bean声明中添加了@JobScope,这使我能够访问作业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 {
// 获取 jobExecution.getJobId(),处理数据的 bean
}
}
我在XML中声明了作业,如下所示:
<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 [DEBUG] [main] [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.
英文:
In my Spring batch project (Spring Boot version 2.3.4.RELEASE, Java 1.8), I have a processor component that needs to access the Job Id (for tracking purpose). I added @JobScope to the bean declaration and this allows me to access the 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
}
I declared the Job in XML like this:
<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>
The XML configuration is loaded as:
@Configuration
@EnableAutoConfiguration
@ImportResource("classpath:batch-job.xml")
public class XMLConfigurationLoader {
}
The Job is scheduled like this:
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());
}
When I build and run the project in a Linux OS server and OpenJDK 1.8, I get the following error.
***************************
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
I have enabled debug mode and see the same error. How can I troubleshoot this? Can you please give some pointers?
Update 1:
I tried changing JobScope to StepScope, and see a similar exception.
2020-10-15 10:53:02.651 [DEBUG] [main]
[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.
答案1
得分: 0
你可以使用 @StepScope
替代 @JobScope
。你可以使用 stepExecution.getJobExecution()
来获取 jobExecution。然后就像你提到的那样,你可以获得 jobId。
英文:
You can use @StepScope
instead of @JobScope
. You can use stepExecution.getJobExecution()
to get the jobExecution. Then you as you have mentioned you can get the jobId.
答案2
得分: 0
我通过实现StepExecutionListener使这个工作起来了。这样可以访问StepExecution对象,从中我们可以获取到任务的Id。
@Component("dealerItemProcessor")
public class DealerItemProcessor implements ItemProcessor<Dealer, Dealer>, StepExecutionListener {
private StepExecution stepExecution;
@Override
public Dealer process(final Dealer dealer) throws Exception {
// 像这样获取唯一的JobId - stepExecution.getJobExecutionId()
// 处理逻辑
}
@Override
public void beforeStep(StepExecution stepExecution) {
// 获取stepExecution对象
this.stepExecution = stepExecution;
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
}
这个解决方案通过提供一个替代方法来解决了获取JobId的需求。但它并没有解决问题中提到的Bean创建异常。
英文:
I got this to work by implementing the StepExecutionListener. This gives access to the StepExecution object, from which we get the 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;
}
}
This solution solves the need to get JobId by providing an alternate. It does not solve the Bean creation exception posted in the question.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论