Java/오류노트

[Java/오류노트] Solved - Annotation-specified bean name 'xxxController' for bean class [xxxController] conflicts with existing, non-compatible bean definition of same name and class [xxxController]

adjh54 2024. 1. 10. 17:53
728x170
해당 글에서는 동일한 이름의 Controller를 생성하였을 때 발생하는 오류와 이에 대해 해결하는 방법에 대해 알아봅니다.

 

 

1) 문제점


💡 문제점

- 아래와 같은 문제가 발생하였습니다.


Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'xxxController' for bean class [xxxController] conflicts with existing, non-compatible bean definition of same name and class [xxxController]

- 해당 오류는 동일한 이름을 가진 두 개의 빈 정의가 서로 다른 클래스와 충돌할 때 발생합니다. 이 특정 경우에는 'xxxController'라는 빈과 해당 클래스 'xxxController' 사이에 충돌이 발생하고 있습니다.
- 이 오류는 이미 응용 프로그램의 다른 위치에서 동일한 이름이지만 다른 클래스를 가진 빈이 이미 정의되어 있어 충돌이 발생한다는 것을 나타냅니다.

 

Annotation-specified bean name 'xxxController' for bean class [xxxController] conflicts with existing, non-compatible bean definition of same name and class [xxxController]

 

 

💡 아래와 같이 Question1To10Controller가 동일한 이름에 패키지만 다르게 존재하기 때문에 발생하는 오류입니다.

 

 

 

 

2) 해결방법


💡 해결방법

- 기본적으로 빈을 따로 지정하지 않으면 ‘이름’으로 등록합니다. 따라서 동일한 이름을 가진 빈이 여러 개 있을 경우 충돌을 발생할 수 있습니다.
- 이렇게 빈 정의와 충돌하지 않기 위해서는 ‘하나의 이름을 변경하거나 Controller 이름을 지정’해주는 방식으로 해결할 수 있습니다.

 

 

1. @RestController의 value 속성으로 파일명은 동일하지만 value를 통해 컨트롤러 이름을 지정합니다.


💡 Question1To10Controller

- v1의 Question1To10Controller는 그대로 사용합니다.
package com.multiflex.multiflexdoitcoding.v2.controller;

@Slf4j
@RestController
@RequestMapping("/api/v1/question")
public class Question1To10Controller {
}

 

 

 

💡 Question1To10Controller

- v2의 Question1To10Controller에서는 V2Question1To10Controller로 이름을 지정합니다.
package com.multiflex.multiflexdoitcoding.v2.controller;

@Slf4j
@RestController(value = "V2Question1To10Controller")
@RequestMapping("/api/v1/question")
public class Question1To10Controller {
}

 

 

💡 [참고] RestController API 문서
 

RestController (Spring Framework 6.1.2 API)

The value may indicate a suggestion for a logical component name, to be turned into a Spring bean in case of an autodetected component.

docs.spring.io

 

 

 

2. BeanNameGenerator를 활용하는 방법 : Bean 이름 자동 생성


💡 BeanNameGenerator를 활용하는 방법 : Bean 이름 자동 생성

- 아래와 같은 클래스를 생성하고 Applcation @SpringBootApplication을 통해 애플리케이션이 시작될 때, 클래스를 스캔하여 수행하면 빈의 이름을 자동 생성해 줍니다.

1.generateBeanName() : BeanDefinition과 BeanDefinitionRegistry를 매개변수로 받아 빈 이름을 생성합니다. 이때, AnnotatedBeanDefinition으로 형변환하여 generateFullBeanName 메서드를 호출하여 전체 빈 이름을 생성합니다.

2. generateFullBeanName():
주어진 AnnotatedBeanDefinition의 메타데이터에서 클래스 이름을 가져와 전체 빈 이름을 생성합니다.
package com.multiflex.multiflexdoitcoding;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;

/**
 * Bean 이름을 패키지 기준으로 지정합니다.
 *
 * @author : lee
 * @fileName : CustomBeanNameGenerator
 * @since : 1/10/24
 */
@Slf4j
public class CustomBeanNameGenerator implements BeanNameGenerator {
    @Override
    public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
        final String result;
        result = generateFullBeanName((AnnotatedBeanDefinition) beanDefinition);
        System.out.println("beanDefinition:: " + beanDefinition + "result :: " + result);
        return result;
    }

    private String generateFullBeanName(final AnnotatedBeanDefinition definition) {
        return definition.getMetadata().getClassName();
    }
}

 

 

 

 

 

 

💡 xxxApplication.java

- 해당 클래스에서는 CustomBeanNameGenerator()을 통해 메타데이터에서 패키지 이름을 가져와 전체 빈 이름 생성하도록 구성되어 있습니다.
package com.multiflex.multiflexdoitcoding;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(nameGenerator = CustomBeanNameGenerator.class)
public class MultiflexDoitCodingApplication {

    public static void main(String[] args) {
        SpringApplication.run(MultiflexDoitCodingApplication.class, args);
    }

}

 

 

3) 해결 화면


💡 해결화면

- 애플리케이션을 수행하였을 때 아래와 같이 재 구성된 패키지 이름이 Bean 이름으로 등록되었습니다.


- 아래와 같이 서버가 잘 수행됨을 확인하였습니다.

 

 

 

 

 

오늘도 감사합니다. 😀

 

 

 

그리드형