• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

V2 ConcreteProxyController 빈 중복 에러 (SpringBoot V3)

23.06.28 22:39 작성 23.06.30 15:18 수정 조회수 370

0

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오) 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예

[질문 내용]
안녕하세요, 영한님! 먼저 이렇게 좋은 강의를 들을 수 있게 되어서 너무 기쁘고 감사드립니다.

먼저 저는 SpringBoot 3.0.5 버전 사용중입니다.

그렇기 때문에 어쩔 수 없이 @RequestMapping으론 컴포넌트 스캔 대상이 되지 않기 때문에 V2 컨트롤러에는 @RestController가 붙어있습니다.

구체 클래스 기반 프록시 V2에 적용할 때, 프록시 컨트롤러를 빈으로 등록하려고 하니 아래처럼 빈이 중복으로 등록된다고 오류가 발생하였습니다.

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

Description:

The bean 'orderControllerV2', defined in class path resource [me/iseunghan/hello/proxy/app/v2/concrete_proxy/ConcreteProxyConfig.class], could not be registered. A bean with that name has already been defined in file [/Users/iseunghan/workspaces/study/lecture-spring-advanced/proxy/build/classes/java/main/me/iseunghan/hello/proxy/app/v2/OrderControllerV2.class] and overriding is disabled.

Action:

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


Process finished with exit code 1

그래서 로그에 친절하게 나와있는대로 application.yaml에 아래 설정을 추가하니 정상적으로 실행 및 테스트가 되었습니다.

application.yaml

spring.main.allow-bean-definition-overriding: true

혹시 이와 같은 방법 이외에는 다른 방법이 없을지 여쭤보고 싶습니다..! 감사합니다.

답변 2

·

답변을 작성해보세요.

0

i seunghan님의 프로필

i seunghan

질문자

2023.07.25

안녕하세요, 답변 감사드립니다. 하지만 뭔가 명확한 답변을 못받아 다시 질문 드립니다..

 

일단 제가 생각한 빈이 중복된 이유는 다음과 같습니다.

  1. @RestController가 붙어있는 클래스가 먼저 빈으로 등록

  2. @Configuration 내부에 @Bean으로 등록하려는 빈이 이미 1번에서 등록이 되어 중복 등록에 대한 오류가 생긴 것 입니다.

스프링부트 버전 3 이상에서는 인터페이스에 @RestController를 붙여줘야만 컨트롤러로 인식하여 구현체가 구현했을 때 엔드포인트 매핑이 된다는 것입니다.

현재 강의에서는 인터페이스 기반 프록시를 구현중이라 어쩔수 없이 컨트롤러 코드에 @RestController를 붙여야 하는 상황인데.. @RestController를 제거하면 URLMapping이 정상적으로 이루어지지 않습니다.. 이럴 때에는 어떻게 하면 좋을지 궁금합니다.

 

아래 코드 첨부드립니다.

@RequiredArgsConstructor
@RestController
public class OrderControllerV2 {

    private final OrderServiceV2 orderService;

    @GetMapping("/v2/request")
    public String request(String itemId) {
        orderService.orderItem(itemId);
        return "ok";
    }

    @GetMapping("/v2/no-log")
    public String nolog() {
        return "ok";
    }

}
public class OrderControllerConcreteProxy extends OrderControllerV2 {
    private final OrderControllerV2 target;
    private final LogTrace logTrace;

    public OrderControllerConcreteProxy(OrderControllerV2 target, LogTrace logTrace) {
        super(null);
        this.target = target;
        this.logTrace = logTrace;
    }

    @Override
    public String request(String itemId) {
        TraceStatus status = null;
        try {
            status = logTrace.begin(this.getClass().getSimpleName() + ".save()");
            String response = target.request(itemId);
            logTrace.end(status);
            return response;
        } catch (Exception e) {
            logTrace.exception(status, e);
            throw e;
        }
    }

    @Override
    public String nolog() {
        TraceStatus status = null;
        try {
            status = logTrace.begin(this.getClass().getSimpleName() + ".save()");
            String response = target.nolog();
            logTrace.end(status);
            return response;
        } catch (Exception e) {
            logTrace.exception(status, e);
            throw e;
        }
    }
}
@Configuration
public class ConcreteProxyConfig {

    @Bean
    public OrderRepositoryV2 orderRepositoryV2(LogTrace logTrace) {
        OrderRepositoryV2 orderRepositoryV2 = new OrderRepositoryV2();
        return new OrderRepositoryConcreteProxy(orderRepositoryV2, logTrace);
    }
    @Bean
    public OrderServiceV2 orderServiceV2(LogTrace logTrace) {
        OrderServiceV2 orderServiceV2 = new OrderServiceV2(orderRepositoryV2(logTrace));
        return new OrderServiceConcreteProxy(orderServiceV2, logTrace);
    }

    @Bean
    public OrderControllerV2 orderControllerV2(LogTrace logTrace) {
        OrderControllerV2 orderControllerV2 = new OrderControllerV2(orderServiceV2(logTrace));
        return new OrderControllerConcreteProxy(orderControllerV2, logTrace);
    }
}
@Import(ConcreteProxyConfig.class)
@SpringBootApplication(scanBasePackages = {"me.iseunghan.hello.proxy.app.v2"})
public class ProxyApplication {

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

    @Bean
    public LogTrace logTrace() {
        return new ThreadLocalLogTrace();
    }
}

패키지 구조

image

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2023.06.30

안녕하세요, 인프런 AI 인턴입니다.

중복으로 빈이 등록된 오류가 발생했다는 내용이군요. 이러한 오류는 동일한 이름의 빈이 여러 곳에서 중복으로 등록되었을 때 발생합니다.

오류 메시지를 보면 orderControllerV2라는 이름의 빈이 ConcreteProxyConfig.classOrderControllerV2.class에 중복으로 등록되었다고 나와있습니다.

이러한 경우, 스프링은 이름이 같은 두 개의 빈을 구분하지 못해 오류가 발생하게 됩니다. 이 문제를 해결하기 위해서는 중복으로 등록된 빈 중 하나를 제거하거나, 빈의 이름을 변경하여 충돌을 피해야 합니다.

따라서, ConcreteProxyConfig.class 또는 OrderControllerV2.class 중 하나에서 빈을 제거하거나, 빈의 이름을 변경하실 수 있도록 해주시면 됩니다.

더 자세한 사항을 알고 싶으신 경우, 스프링의 빈 등록 규칙과 중복 등록되는 이유에 대해 공부해보시면 도움이 되실 것입니다.

더 궁금한 사항이 있다면 언제든지 물어보세요. 도움이 될 수 있도록 최선을 다하겠습니다.