반응형
해당 글에서는 동일한 이름의 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 문서
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 이름으로 등록되었습니다.
- 아래와 같이 서버가 잘 수행됨을 확인하였습니다.
오늘도 감사합니다. 😀
반응형