DevKim
[01] 스프링 Bean과 의존관계 - 컴포넌트 스캔과 자동 의존관계 VS. 직접 스프링 빈 등록 본문
* 의존 관계가 있다는 것은?
- 화면을 붙이고 싶은데, 그러려면 Controller와 view template이 필요하다
-> 그러려면 memberController를 만들어야함
-> memberService를 통해서 회원가입을 하고, data를 조회할 수 있어야함
-> 의존관계가 있다고 표현
[스프링 빈을 등록하는 2가지 방법]
1. 컴포넌트 스캔과 자동 의존관계 설정
2. 자바 코드로 직접 스프링 빈 등록하기
지금까지 1번만 사용했었는데, 영한님 말씀으론 둘다 알아야한다고 하신다.
[ 컴포넌트 스캔과 자동 의존관계 설정]
1. 먼저 MemberController를 생성하고 의존관계를 추가해보았다.
생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다.
이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI(Dependency Injection), 의존성 주입이라고 한다.
이전 테스트에선 개발자가 직접 주입했고, 여기에서는 @Autowired에 의해 스프링이 주입해준다.
하지만 이렇게만 써주면 오류가 난다.
왜?
memberService가 스프링 빈으로 등록되어 있지 않기 때문이다.
아직 memberService는 그냥 순수한 java class이어서 스프링이 알 방법이 없다!!
어노테이션을 걸어줘야 스프링이 뜰 때, 아~ 이건 내가 관리하는 애니까 생성을 해줘야겠구나 한다.
어노테이션을 걸어두면, 다음과 같은 일이 벌어진다
Spring이 뜰 때 먼저 컨테이너라는 통이 생긴다.
이때 컴포넌트 관련된 어노테이션이 있으면, 스프링이 하나씩 다 객체를 생성해서 컨테이너에 등록을 한다.
( 스프링 컨테이너에서 스프링 빈이 관리 된다고 표현함)
@Autowired는 연관관계(선)을 연결해주는 역할이다.
<ex> memberController가 memberService를 사용할 수 있게하고.. 등
*** 정리 ***
@Component 어노테이션이 있으면 스프링 빈으로 자동으로 등록된다
(컴포넌트를 포함하는 @Controller,@Service.. 도 마찬가지!)
* 참고 *
생성자에 @Autowired를 사용하면, 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입한다.
생성자가 1개만 있으면 @Autowired는 생략할 수 있다.
[ 스프링 빈 등록 이미지 ]
다음과 같이 빈과 의존관계가 성립한다.
+) Lombok의 @RequiredArgsConstructor 어노테이션을 사용한 생성자 주입
@RequiredArgsConstructor은 final이 붙거나
@NotNull이 붙은 필드의 생성자를 자동 생성해주는
Lombok의 어노테이션이다.
사실 이 강의를 듣기 전까진 매번 습관처럼 @RequiredArgsConstructor을 붙여서
repository나 service를 가져와서 사용하였다.
이 강의를 듣기 전까진 '생성자 주입'이라는 말이 너무 뜬 구름처럼 느껴졌는데,
생성자를 직접 입력하고, 이를 @Autowired로 직접 입력해서 연결해주니,
의존 관계가 더 명확히 느껴졌다.
[ 자바 코드로 직접 스프링 빈 등록하기 ]
*@Service,@Repository,@Autowired.. 등 어노테이션을 제거하고 진행한다.
(단, Controller는 어쨌든 Spring이 관리하는거라 컴포넌트 스캔으로 올라가게 둬야한다.)
직접 등록하기 위해 SpringConfig 파일을 하나 만들어주었다.
@Configuration : 1개 이상의 Bean을 등록하고 있음을 명시하는 어노테이션
[ 동작 과정 ]
Spring이 뜸
-> memberService와 repository를 둘다 Spring bean에 등록
-> Spring bean에 등록되어있는 repository를 service에 넣어줌
* 현재 실습에서 가정한 것 처럼..
여기서는 향후 메모리 리포지토리를 다른 리포지토리로 변경할 예정이므로,
컴포넌트 스캔 방식 대신에, 위와 같이 자바 코드로 스프링 빈을 설정할 것이다.
??????왜?????
라는 의문이 들었지만..
영한님이 바로 설명해주셨다.
* 실무에서는 주로 정형화된 controller,service,repository 같은 코드는 컴포넌트 스캔을 사용한다.
* 정형화 되어 있지 않거나, 상황에 따라 구현 클래스를 변경해야한다면 설정을 통해 스프링 빈으로 등록한다.
앞서서, 아직 데이터 저장소가 선정되지 않았다는 가상의 시나리오를 짜놨었다.
그래서 지금 일단 memory로 만들고 나중에 교체할건데..
위의 그림에서,
나중에 교체할 때 MemoryMemberRepository를 다른 Repository
(DB에 실제로 연결하는 Repository)로
바꿔치기 할 예정이다.
이때, 기존에 운영중인 코드를 하나도 손대지 않고!!
바꿔치기 하기 위해서 직접 등록하는 것이다
( Repository 이름만 바꿔주면 됨)
+ [@Bean VS. @Component]
문득.. @Bean 과 @Component의 명확한 차이점이 뭔지 머릿속에서 떠오르지 않아서 찾아보았다.
[ @Bean, @Configuration ]
- 개발자가 직접 제어가 불가능한 외부 라이브러리들을 Bean으로 등록할 때 @Bean을 사용한다.
- 개발자가 작성한 '메소드'를 통해 반환되는 객체를 Bean으로 만든다.
[ @Component ]
- 반대로 개발자가 직접 컨트롤이 가능한 Class들의 경우엔 @Component를 사용한다.( 개발자가 개발한 클래스를 Bean으로 등록하고자 하는 경우)
- '클래스' 위에서만 선언될 수 있다.
*참고*
DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있는데,
실무에선 의존 관계가 실행중에 동적으로 변하는 경우는 없기 때문에 생성자 주입을 권장한다고 한다.
*자료 출처*
스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 (김영한)
'Spring Boot' 카테고리의 다른 글
[01] AOP (0) | 2021.05.06 |
---|---|
[01] 회원 관리 예제 - 회원 웹 기능 (홈 화면 추가,등록,조회 화면 추가) (0) | 2021.05.06 |
[01] 회원 관리 예제 - 회원 service 개발 & Test Code 작성 (0) | 2021.05.06 |
[01] 회원 관리 예제 - 비즈니스 요구 사항 정리 & domain과 repository 생성 &Test code 작성 (0) | 2021.05.06 |
[01] 정적 컨텐츠, MVC와 템플릿 엔진, API (0) | 2021.05.06 |