해결된 질문
작성
·
283
1
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.
1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)
[질문 내용]
안녕하세요 강의 잘 보고 있습니다. 최근에 @Autowired 필드 명,@Qualifier, @Primary라는 제목의 강의를 보았는데 궁금한 점이 생겼습니다. 질문 내용이 길어질 거 같아서 죄송스럽지만 여태 배운 내용을 정리해보는 계기가 되고 강사님께서 제가 모르는 부분을 알 수 있는 매개체 역할이 될 거 같아서 강의의 흐름을 정리해보겠습니다.(정리된 부분에서 잘못된 부분이 있을 수 도 있습니다. 글이 정말 길다면 맨 아래의 제가 드리고 싶은 질문을 볼드체로 구분하였습니다.)
처음부터 강의의 흐름을 따라 살펴보면 A클래스가 있고 데이터베이스의 기능을 하는 B클래스와 C클래스가 있다고 가정해보겠습니다. A클래스가 B클래스의 인스턴스가 필요하게 될 때, new 연산자를 통해 B클래스의 인스턴스를 만들어 냅니다. 그렇게 되면 A와 B의 의존 관계가 형성되는데 A내부에서 의존 관계가 형성되어 결합도가 높아지고 이로 인해서 객체지향 설계원칙 중 OCP에 영향을 끼치게 됩니다. 영향을 끼치게 되는 이유가 만약 B클래스가 아닌 C클래스로 기능을 변경하려면 C클래스의 인스턴스를 따로 만들어야 하기 때문입니다.
그래서 이러한 문제를 해결하기 위해서 서비스로직과 구성로직을 따로 구분하게 됩니다. 서비스로직 클래스에서 생성자를 만들어 놓은 후 구성로직 클래스에서 서비스로직 클래스에 만들어 놓은 생성자를 호출하게 됨으로서 각각의 클래스의 역할을 분리해 두었고(SRP 단일 책임 원칙) 서비스로직 클래스에서는 코드의 변경이 필요 없게 되었고 만약 B클래스 대신 C클래스를 서비스로직 클래스에서 사용한다고 하면 서비스로직 클래스에서 코드를 변경하는것이 아닌 구성로직 클래스에서 C클래스를 생성자의 인자로 넘겨줌으로서 적어도 서비스로직 클래스는 기능에 추가에는 열려있고 변경에는 닫혀있는(OCP 개방 폐쇄 원칙)을 따르게 되었습니다. 여기에 추가로 스프링 프레임워크의 @Configuration어노테이션을 구성로직 클래스에 붙이고 각각의 서비스로직의 생성자를 호출하는 메서드의 @Bean어노테이션을 붙임으로서 이를 스프링 컨테이너에 등록할 수 있게 되었고 스프링 컨테이너에 등록된 빈(POJO)객체는 객체를 생성할 때 여러 번 생성할 때 여러 개 생성되는것이 아닌 한개의 메모리만 갖게 되는 싱글톤 패턴이 적용된 클래스를 복잡한 코드의 구현 없이 어노테이션을 붙인것 만으로도 기능을 사용할 수 있게 됩니다. 여기까지가 수동 주입이었습니다.
그리고 자동 주입에 대해서 설명해 주실 때, 수동 주입 처럼 서비스로직의 생성자를 호출해 주는 구성로직을 개발자가 직접 만들어 사용하는것이 아닌 @Component어노테이션을 서비스로직 클래스에 붙이게 되면 @ComponentScan어노테이션이 실행될 때 @Component가 붙은 클래스의 이름(맨 앞글자의 대문자를 소문자로 변경함)을 스프링 컨테이너의 키로 인스턴스가 사용되는 힙메모리 주소가 값인 형태로 저장되게 됩니다. 의존성 주입이 필요하게 될 때 스프링 컨테이너안에 들어있는 빈객체가 존재해야지 (@ComponentScan을 통해 @Component가 붙은 클래스를 스프링 컨테이너안에 넣어야지) @Autowired가 붙은 생성자, 프로퍼티, 세터 혹은 메서드등으로 의존성 주입이 가능하였습니다.
여기서 제가 궁금했던 점이 만약 자동 주입을 사용하는 A클래스가 있을 때 데이터베이스의 기능을 하며 @Component가 붙은 B클래스와 C클래스가 있다고 가정하면 자동 주입을 사용하지 않았을 때 처럼 서비스로직과 구성로직으로 구분하고 의존성 주입을 하는 방식이 아닌 위해 정리한 방식대로 의존성 주입을 하게 되다 보니 만약 타입은 같은데 구현 방법이 다른 B클래스가 아니라 C클래스를 의존성 주입을 하고 싶을 때, 저는 데이터베이스의 기능(인터페이스라고 가정하겠습니다.)으로 의존성 주입을 하는것이 아니라 직접구현된 C클래스의 Impl로 주입을 해야되나 싶었습니다. 결국 아무리 OCP를 지킨다 하더라도 이렇게 무엇인가(인터페이스를 구현한 클래스)를 명시를 해줘야 그 구현된 클래스의 메서드를 사용할 수 있을테니 말이죠.
이 궁금증을 품고 강의를 보던 도중에 조회 빈이 2개 이상 -문제 라는 강의를 보고 @Autowired가 의존성 주입될 매개변수의 타입을 이용해서 @Component가 붙은 같은 타입의 클래스를 매칭 한다는것에 대해 알게 되었고 @Autowired 필드 명,@Qualifier, @Primary 강의를 통해서 궁금증이 풀리는 듯 싶었습니다. 근데 여기서 타입이 같은 두개의 @Component가 붙은 클래스(이전에 언급된 B, C 클래스)의 우선순위를 @Qualifier를 의존성 주입이 될 클래스에 붙여주고(@Qualifier("이름")을 통해서 이름을 설정해줌) 의존성 주입을 하는 생성자의 매개변수에 똑같이 @Qualifier어노테이션을 붙이게 되어 타입이 같은 클래스더라도 두 개를 동시에 사용할 수 없어서 발생되는 예외인 "NoUniqueBeanDefinitionException"이 발생되는 것이 아닌 하나의 빈만 사용하게 되어서 문제가 해결되는 듯 싶었으나 질문 초반에 언급되었던 서비스로직 클래스와 구성로직 클래스 를 다시 언급해보면 SRP와 OCP를 동시에 지키기 위해서 이런 방법이 사용되었는데 자동 주입을 사용하게 될 때, 구성 로직 클래스는 사용하지 않는다고 가정하면 서비스 로직 클래스만 사용하게 되는데 여기서 제 생각은 @Qualifier어노테이션을 붙이게 되는 것이 서비스 로직 클래스에서 OCP가 위반 된것이 아닌가 이런 생각이 듭니다. 결국 코드의 로직을 확장하기 위해서 서비스 로직 클래스 안에 있는 생성자의 매개변수를 변경하게 되었으니까요. 아니면 저의 이러한 생각이 잘못되었는지도 궁금합니다. 단순히 어노테이션 하나만 붙였다고 해서 OCP가 위반이 되는것은 아닌지, 이러한 내용이 OCP와 관련이 없다던지, 강사님의 의견을 듣고 싶습니다.
글이 정말 긴데 저의 궁금증을 정확히 묘사하기 위한 역할로만 봐주시면 감사하겠습니다. 시간 나실 때 천천히 답변 달아주시면 좋겠습니다. 긴 글 읽어주셔서 감사드립니다.
답변 1
2
안녕하세요. 이승훈님, 공식 서포터즈 David입니다.
@Qualifier를 사용할 때 OCP의 위반여부에 대한 것은 아래 글 답변을 참고해주세요:)
https://www.inflearn.com/questions/160058
감사합니다.
이미 있었던 질문이었네요 감사합니다!