• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

필드 주입 시, 질문 드립니다.

20.09.27 18:14 작성 조회수 383

2

안녕하세요. 선생님 강의 너무 잘 듣고 있습니다.

.

이번 "주입 방법" 강의 들으면서 궁금한게 생겼습니다.

3번 째 방법인 필드 주입 인 경우 입니다.

.

지금 현재 햇갈리는게 컴포넌트 스캔과 자동 의존 관계 주입 순서인데요.

.

  1.  컴포넌트 스캔에 의해 스프링 컨테이너에 Bean 이 생성 되고, 생성자 필드 주입 시 바로 주입
  2. 수정자(Setter), 필드 의존 관계 자동 주입

으로 알 고 있습니다. 이 개념으로 MemberServiceImpl 클래스에서 OrderServiceImpl 클래스의 메소드를 사용하려는 테스트를 진행하였습니다.

.

이유는 bean 생성 로그를 확인하였을때, MemberServiceImpl 클래스에서 OrderServiceImpl 를 사용하려는 시점에 bean 이 생성과 주입이 되어 있다고 생각했기 때문입니다.

.

=========== [S] 로그 ===========

// 빈 생성 및 생성자 필드 주입 완료 로그 확인

Creating shared instance of singleton bean 'autoAppConfig'

Creating shared instance of singleton bean 'rateDiscountPolicy'

Creating shared instance of singleton bean 'memberServiceImpl'

Creating shared instance of singleton bean 'memoryMemberRepository'

Autowiring by type from bean name 'memberServiceImpl' via constructor to bean named 'memoryMemberRepository'

Creating shared instance of singleton bean 'orderServiceImpl'

Autowiring by type from bean name 'orderServiceImpl' via constructor to bean named 'memoryMemberRepository'

Autowiring by type from bean name 'orderServiceImpl' via constructor to bean named 'rateDiscountPolicy'

=========== [E] 로그 ===========

.

테스트는

맨 처음 다음과 같이 MemberServiceImpl 클래스에 OrderServiceImpl 를 필드 주입 했습니다.

.

OrderServiceImpl 클래스는 컴포넌트 스캔에 의해 생성 될 때, 생성자 주입이라 스프링 컨테이너에 올라가며 주입까지 된 상태이기에

MemberServiceImpl 클래스에서 간단하게 OrderServiceImpl 를 필드 주입 하여 사용할 수 있을 줄 알았습니다. (구현체를 이미 주입 받았다고 생각함)

하지만 다음과 같이 OrderServiceImpl 빈이 없다는 오류가 뜨는데....

NoSuchBeanDefinitionException: No qualifying bean of type 'hello.core.order.OrderServiceImpl' 

제가 생각하고 있는 주입 순서가 어떤게 잘 못 되었는지 궁금합니다 !

(궁극적으로 제가 하려는 행위는 이미 구현체가 주입 된 bean을 다른 클래스에서 사용하기 위해, @Autowired 필드 주입만 하여 사용하고 싶은 행위 입니다! )

답변 3

·

답변을 작성해보세요.

10

안녕하세요. 준상님

확인을 해보니 우선 수동 빈 등록을 사용하셨네요^^

결론부터 말씀드리면 다음 둘중 하나를 선택하시면 문제없이 동작합니다. 물론 첫번째 방법이 좋습니다.

1. @Autowired OrderServiceImpl 대신에 OrderService로 주입받으세요.

2. @Bean을 등록할 때 반환 타입을 OrderService 대신에 OrderServiceImpl로 등록해주세요.

사실 이 케이스는 고민하지 않고 첫번째 방식을 사용하셔야 합니다! 인터페이스가 있다면 의존관계 주입은 인터페이스에 의존하도록 설계해야 합니다.

스프링의 내부 초기화는 사실 매우 복잡한 사이클을 거쳐서 일어납니다. 정말 모든 빈이 완벽하게 생성된 다음에 빈이 주입된다면 이런 문제가 발생하지 않겠지만, 사실은 빈이 생성되면서 필요한 의존관계도 체크하고, 의존관계 주입도 함께 일어납니다. 그런데 의존관계 주입 시점에 대상 클래스의 객체 인스턴스가 이미 만들어져 있으면 상관이 없는데, 아직 만들어지지 않았으면, 인스턴스가 없으므로, 객체 인스턴스의 타입을 확인할 수 있는 방법이 없습니다. 그래서 이때는 @Bean같은 경우 반환 타입을 기준으로 의존관계 주입을 체크합니다. 여기서는 반환타입이 OrderService 인터페이스가 되지요. 그런데 @Autowird로 OrderServiceImpl 타입을 달라고 했는데, 스프링은 아직 OrderServiceImpl과 관련된 빈 객체를 생성한 적이 없기 때문에, 이 타입을 알지 못합니다. @Bean으로 등록한 것도 OrderService 라는 인터페이스 타입으로 등록했기 때문에 더더욱 타입을 찾을 방법이 없는 것이지요.

그런데 @Autowird OrderService라고 하면 아직 등록된 빈 객체 인스턴스가 없어도, @Bean에서 반환타입으로 지정한 OrderService타입으로 빈을 찾을 수 있기 때문에 스프링은 해당 빈을 찾아서 객체 인스턴스를 생성하고 주입해줍니다^^

조금 어려운 내용인데요. 사실 인터페이스를 만들었다면 인터페이스를 사용해야합니다! 그리고 인터페이스를 통해서 주입받아야 합니다^^!

도움이 되셨길 바래요^^!

3

준상이님의 프로필

준상이

질문자

2020.09.28

답변 메일 잘 받았습니다 !

해결 감사합니다 ㅠㅎㅎ

0

안녕하세요. 준상이님^^ 좋은 질문입니다.

대략 어떤 문제인지 알것 같은데요. 아마 여러 테스트가 있어서 꼬였을 것 같아요.

zipkyh@naver.com으로 전체 코드를 압축해서 보내주세요^^!

그리고 어떤 테스트를 실행할 때 오류가 발생하는지도 꼭 말씀해주세요^^