You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 2中XML定义Bean时StepScope Bean重复注册问题

问题:Spring Boot 2中纯XML配置触发BeanDefinitionOverrideException异常

现象

在Spring Boot 2环境下,仅通过SpringApplication.setSources()加载XML配置文件启动应用时,会抛出BeanDefinitionOverrideException异常;但改用Java配置方式,或通过@ImportResource引入同一份XML配置时,应用可正常启动。当前无法升级到Spring Boot 3。

错误日志

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

Description:

The bean 'scopedTarget.reader', defined in BeanDefinition defined in file [/Users/username/IdeaProjects/testing-spring-batch/target/classes/org/example/Reader.class], could not be registered. A bean with that name has already been defined in file [/Users/username/IdeaProjects/testing-spring-batch/target/classes/org/example/Reader.class] and overriding is disabled.

Action:

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

相关代码

Main.java

@SpringBootApplication
@EnableBatchProcessing
public class Main {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Main.class);
        app.setSources(Collections.singleton("classpath:launch-context.xml"));
        System.exit(SpringApplication.exit(app.run(args).getParent()));
    }
}

Reader.java

@Component
@StepScope
public class Reader implements ItemReader<String> {
// return a list of string
}

XML配置(launch-context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:batch="http://www.springframework.org/schema/batch"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
        http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <batch:job id="test">
        <batch:step id="companyStep">
            <batch:tasklet>
                <batch:chunk reader="reader" processor="processor"
                             writer="writer" commit-interval="1" />
            </batch:tasklet>
        </batch:step>
    </batch:job>
</beans>

排查结论

  • scopedTarget.reader这个StepScope代理Bean被重复注册:一次来自Spring注解自动扫描(@Component+@StepScope),另一次来自Step Scope后置处理器的调用。
  • Java配置场景下,ScopeConfiguration类会将Step Scope的自动代理标志设为false,避免重复代理;但XML配置场景下,StepScope通过CoreNamespaceUtils.checkForScope()调用原生构造器创建,自动代理默认开启,导致重复生成代理Bean。
  • @ImportResource引入XML时无异常,是因为资源在应用上下文刷新(Bean定义解析完成后)才被处理,时机与注解扫描不冲突;但当前场景需要动态传入XML资源,无法使用该方式。

规避方案

针对动态传入XML的场景,可选择以下方案:

1. 启用Bean定义覆盖(最简单但需注意风险)

直接允许Bean定义覆盖,可通过代码或配置文件设置:

  • 代码方式:
SpringApplication app = new SpringApplication(Main.class);
app.setAllowBeanDefinitionOverriding(true); // 开启覆盖
app.setSources(Collections.singleton("classpath:launch-context.xml"));
  • 配置文件方式(application.properties):
spring.main.allow-bean-definition-overriding=true

注意:该方式会允许同名Bean覆盖,可能引发意外的Bean替换风险,需确认业务场景无冲突。

2. 自定义StepScope并关闭自动代理

通过配置类手动注册StepScope,设置autoProxy=false,替代XML自动生成的StepScope:

@Configuration
public class CustomStepScopeConfig {
    @Bean
    public static StepScope stepScope() {
        StepScope stepScope = new StepScope();
        stepScope.setAutoProxy(false); // 关键:关闭自动代理,避免重复生成scopedTarget bean
        stepScope.setScopeName("step");
        return stepScope;
    }
}

确保该配置类被Spring扫描到(放在@SpringBootApplication所在包或子包下),即可让XML加载时使用自定义的StepScope,避免重复代理。

3. 调整XML资源加载时机

模拟@ImportResource的延迟加载逻辑,通过ApplicationContextInitializer在上下文初始化阶段加载XML,而非直接设置为应用源:

public static void main(String[] args) {
    SpringApplication app = new SpringApplication(Main.class);
    app.addInitializers((ApplicationContextInitializer<GenericApplicationContext>) context -> {
        // 手动加载XML Bean定义
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions(new ClassPathResource("launch-context.xml"));
    });
    System.exit(SpringApplication.exit(app.run(args).getParent()));
}

该方式让XML Bean定义的加载时机与注解扫描协调,避免StepScope后置处理器重复触发代理。

4. 调整Reader的Scope配置方式

移除Reader类上的@Component和@StepScope注解,改为在XML中直接定义Reader Bean并指定StepScope:

<!-- 在launch-context.xml中添加 -->
<bean id="reader" class="org.example.Reader" scope="step"/>

这样仅通过XML生成scopedTarget代理Bean,避免注解扫描带来的重复注册。


内容的提问来源于stack exchange,提问作者Antho Christen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 02:45:37