Spring Boot配置多个Spring StateMachine时启动报Bean重复注册错误
问题成因
这个报错和两个状态机工厂之间的命名无关,冲突发生在配置类自身的bean注册阶段:
- Spring会将所有
@Configuration标注的类注册为容器bean,默认bean名称为类名首字母小写。你的订单状态机配置类名为OrderStateMachine,对应的默认bean名就是orderStateMachine。 - 你在
@EnableStateMachineFactory(name = "orderStateMachine")中,又给要生成的StateMachineFactory实例指定了完全相同的bean名。 - Spring Boot 2.1+版本默认禁止bean定义覆盖,容器启动阶段扫描到两个同名bean的注册请求就会直接抛出启动失败错误,此时还没走到依赖注入环节,所以你写的
@Qualifier注入逻辑根本没机会执行。
另外你的代码里还存在状态配置的参数类型/枚举引用错误,就算解决重名问题也会后续报错:
- 订单状态机配置中,
initial()和end()方法要求传入**状态枚举(OrderState)**类型参数,你误引用了OrderEvent事件枚举的值:ITEM_PICKED属于OrderEvent,ORDER_CONFIRMED属于OrderState,你写反了枚举类前缀。 - 支付状态机配置存在完全相同的问题,
initial()和end()误引用了PaymentEvent事件枚举值,不符合方法参数类型要求。
修复方案
按顺序修复以下问题即可:
- 解决bean重名冲突,二选一即可:
- 方案一:重命名配置类,避免配置类默认bean名和工厂名冲突。比如将
OrderStateMachine改名为OrderStateMachineConfig、PaymentStateMachine改名为PaymentStateMachineConfig,此时配置类默认bean名为orderStateMachineConfig、paymentStateMachineConfig,和你指定的工厂名不再冲突。 - 方案二:给配置类显式指定bean名,无需修改类名。在
@Configuration注解上显式指定value即可,示例:
支付状态机配置同理,给@Configuration("orderStateMachineConfig") @EnableStateMachineFactory(name = "orderStateMachine") public class OrderStateMachine extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> { // 配置内容 }@Configuration指定独立的bean名即可。
- 方案一:重命名配置类,避免配置类默认bean名和工厂名冲突。比如将
- 修正状态配置的枚举引用错误:
- 订单状态机配置中,
initial()传入订单状态枚举的初始态,end()传入订单状态枚举的终态,示例:@Override public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states) throws Exception { states.withStates() .initial(OrderState.ORDER_INITIATED) .end(OrderState.ORDER_CONFIRMED) .end(OrderState.ORDER_CANCELLED) .states(EnumSet.allOf(OrderState.class)); } - 支付状态机配置同理,
initial()和end()都传入PaymentState类型的枚举值,示例:@Override public void configure(StateMachineStateConfigurer<PaymentState, PaymentEvent> states) throws Exception { states.withStates() .initial(PaymentState.PAYMENT_INITIATED) .end(PaymentState.PAYMENT_COLLECTED) .end(PaymentState.PAYMENT_CANCELLED) .states(EnumSet.allOf(PaymentState.class)); }
- 订单状态机配置中,
- (可选)如果你不需要按名称获取工厂,其实可以省略
@EnableStateMachineFactory的name属性,由于两个工厂的泛型参数不同,Spring可以直接按类型区分注入,不需要额外指定名称和@Qualifier。
内容的提问来源于stack exchange,提问作者Chandan Mishra
相关产品推荐
相关产品推荐

