Skip to content

RabbitJackson2Configuration and RabbitJacksonConfiguration conflict when Jackson 2.x is on classpath (e.g. Eureka Client) #1776

Description

@HyoungUkJo

[Bug] BeanDefinitionOverrideException when using spring-modulith-events-amqp with Eureka Client

How I Found This

I was implementing the Outbox Pattern in an MSA environment and added spring-modulith-events-amqp as a dependency.
After that, I added spring-cloud-netflix-eureka-client for service discovery, and the application failed to start with the error below.

Environment

  • Spring Boot: 4.1.0
  • Spring Modulith: 2.1.0
  • Spring Cloud: 2025.1.2 (including Eureka Client)

Error Message

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

Description:

The bean 'rabbitTemplateCustomizer', defined in class path resource
[org/springframework/modulith/events/amqp/RabbitJacksonConfiguration.class],
could not be registered. A bean with that name has already been defined in class path resource
[org/springframework/modulith/events/amqp/RabbitJackson2Configuration.class]
and overriding is disabled.

Action:

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

Root Cause Analysis

spring-modulith-events-amqp contains two configuration classes:

Class Based on Activation Condition Status
RabbitJacksonConfiguration Jackson 3.x (JsonMapper) @ConditionalOnClass(JsonMapper.class) Current
RabbitJackson2Configuration Jackson 2.x (ObjectMapper) @ConditionalOnClass(ObjectMapper.class) @Deprecated

Before adding Eureka Client:

  • Only JsonMapper (Jackson 3.x) exists on the classpath
  • Only RabbitJacksonConfiguration is activated → no conflict
  • RabbitJackson2Configuration is inactive because ObjectMapper is not present

After adding Eureka Client:

  • Eureka Client brings com.fasterxml.jackson (Jackson 2.x) onto the classpath
  • ObjectMapper now exists, satisfying RabbitJackson2Configuration's activation condition
  • Both classes attempt to register a bean named rabbitTemplateCustomizer → conflict!

Root Cause

Both classes attempt to register a bean with the same name (rabbitTemplateCustomizer) without being aware of each other.

While RabbitJacksonConfiguration (current) is declared before RabbitJackson2Configuration in AutoConfiguration.imports, this ordering is not officially guaranteed by Spring.

Two fixes are needed:

  1. Add before to RabbitJacksonConfiguration → guarantee the current version is always registered first
  2. Add @ConditionalOnMissingBean to RabbitJackson2Configuration → skip registration if the bean already exists
// RabbitJacksonConfiguration (current) — add before
@AutoConfiguration(before = RabbitJackson2Configuration.class)  // needs to be added
@ConditionalOnClass({ RabbitTemplate.class, JsonMapper.class })
class RabbitJacksonConfiguration {
    @Bean
    @ConditionalOnBean(JsonMapper.class)
    RabbitTemplateCustomizer rabbitTemplateCustomizer(JsonMapper mapper) { ... }
}

// RabbitJackson2Configuration (deprecated) — add @ConditionalOnMissingBean
@Deprecated
@AutoConfiguration
@ConditionalOnClass({ RabbitTemplate.class, ObjectMapper.class })
class RabbitJackson2Configuration {
    @Deprecated
    @Bean
    @ConditionalOnBean(ObjectMapper.class)
    @ConditionalOnMissingBean(name = "rabbitTemplateCustomizer")  // needs to be added
    RabbitTemplateCustomizer rabbitTemplateCustomizer(ObjectMapper mapper) { ... }
}

Workaround

Add the following to application.yml to exclude RabbitJackson2Configuration:

spring:
  autoconfigure:
    exclude:
      - org.springframework.modulith.events.amqp.RabbitJackson2Configuration

Korean (원본)

[버그] spring-modulith-events-amqp와 Eureka Client 함께 사용 시 BeanDefinitionOverrideException 발생

발견 경위

MSA 환경에서 아웃박스 패턴(Outbox Pattern)을 구현하기 위해 spring-modulith-events-amqp 의존성을 추가했습니다.
이후 서비스 디스커버리를 위해 spring-cloud-netflix-eureka-client를 추가했더니 애플리케이션 기동 시 아래와 같은 오류가 발생했습니다.

환경

  • Spring Boot: 4.1.0
  • Spring Modulith: 2.1.0
  • Spring Cloud: 2025.1.2 (Eureka Client 포함)

오류 메시지

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

Description:

The bean 'rabbitTemplateCustomizer', defined in class path resource
[org/springframework/modulith/events/amqp/RabbitJacksonConfiguration.class],
could not be registered. A bean with that name has already been defined in class path resource
[org/springframework/modulith/events/amqp/RabbitJackson2Configuration.class]
and overriding is disabled.

Action:

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

원인 분석

spring-modulith-events-amqp 내부에는 두 개의 설정 클래스가 존재합니다.

클래스 기반 활성화 조건 상태
RabbitJacksonConfiguration Jackson 3.x (JsonMapper) @ConditionalOnClass(JsonMapper.class) 최신
RabbitJackson2Configuration Jackson 2.x (ObjectMapper) @ConditionalOnClass(ObjectMapper.class) @Deprecated

Eureka Client 추가 전:

  • classpath에 JsonMapper(Jackson 3.x)만 존재
  • RabbitJacksonConfiguration만 활성화 → 충돌 없음
  • RabbitJackson2ConfigurationObjectMapper가 없으므로 비활성화

Eureka Client 추가 후:

  • Eureka Client가 com.fasterxml.jackson(Jackson 2.x)을 classpath에 추가
  • ObjectMapper가 생기면서 RabbitJackson2Configuration 활성화 조건 충족
  • 두 설정 클래스가 동시에 rabbitTemplateCustomizer라는 같은 이름의 빈 등록 시도 → 충돌!

근본 원인

두 클래스가 서로를 인식하지 못하고 동시에 같은 이름의 빈(rabbitTemplateCustomizer) 등록을 시도합니다.

AutoConfiguration.imports 파일 순서상 RabbitJacksonConfiguration(신버전)이 먼저 선언되어 있어 일반적으로는 신버전이 먼저 등록되지만, 이 순서는 Spring이 공식적으로 보장하지 않습니다.

따라서 두 가지 수정이 모두 필요합니다:

  1. RabbitJacksonConfigurationbefore 추가 → 항상 신버전이 먼저 등록되도록 순서 보장
  2. RabbitJackson2Configuration@ConditionalOnMissingBean 추가 → 이미 빈이 있으면 등록하지 않도록
// RabbitJacksonConfiguration (신버전) — before 추가
@AutoConfiguration(before = RabbitJackson2Configuration.class)  // 추가 필요
@ConditionalOnClass({ RabbitTemplate.class, JsonMapper.class })
class RabbitJacksonConfiguration {
    @Bean
    @ConditionalOnBean(JsonMapper.class)
    RabbitTemplateCustomizer rabbitTemplateCustomizer(JsonMapper mapper) { ... }
}

// RabbitJackson2Configuration (구버전) — @ConditionalOnMissingBean 추가
@Deprecated
@AutoConfiguration
@ConditionalOnClass({ RabbitTemplate.class, ObjectMapper.class })
class RabbitJackson2Configuration {
    @Deprecated
    @Bean
    @ConditionalOnBean(ObjectMapper.class)
    @ConditionalOnMissingBean(name = "rabbitTemplateCustomizer")  // 추가 필요
    RabbitTemplateCustomizer rabbitTemplateCustomizer(ObjectMapper mapper) { ... }
}

임시 해결 방법

application.yml에 아래 설정을 추가하여 RabbitJackson2Configuration을 제외합니다.

spring:
  autoconfigure:
    exclude:
      - org.springframework.modulith.events.amqp.RabbitJackson2Configuration

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions