스프링 입문 - 스프링 빈과 의존관계
이 글은 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 커리큘럼에 맞춰서 작성된 글입니다😀
스프링 빈을 등록하는 방법은 2가지가 있다.
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
근데 모르는 용어가 하나 둘씩 등장한다😯
스프링 빈은 뭐고 스프링 컨테이너는 뭘까?
간단하게 설명하면 스프링 빈은 스프링에서 활용하는 객체고,
스프링 컨테이너는 빈이 활동할 수 있는 환경이다. 빈의 생명주기를 관리한다고 보면 된다.
검색해보면 자세한 설명글이 많은데 GilLog님의 글이 이해가 잘됐다!
물론 강의에서도 잘 설명해주신다😄
컴포넌트 스캔과 자동 의존관계 설정
hello/hellospring
에 controller
라는 리포지토리를 생성 후 MemberController.java
를 만들어주자.
그리고 코드를 다음과 같이 적어주자.
일단 확인해야할 점이 3가지가 있다.
첫 번째로, 필드로 선언된 memberService
를 new를 통해 인스턴스 생성을 하지 않은 점이다.
new를 통해 만들어서 쓸 수는 있으나 memberSerivce
에 구현된 내용은 딱히 여러 인스턴스를 관리하면서
별도로 운용될 필요가 없기 때문에 1개만 스프링 컨테이너에 등록해놓고 사용해도 문제가 없다!
따라서 new가 아닌 위의 코드처럼 생성자를 활용해 받아와서 등록하는 방식을 취한다.
두 번째로, 위 코드는 Run 했을 때 스프링에서 인식하지 못한다.
어노테이션이 달려있는 것들만 빈으로 만들어서 스프링 컨테이너에서 관리하게 되는데
MemberController
는 지금 어노테이션이 등록되지 않은 상태여서 그렇다.
이 때 Run을 하면 memberService가 스프링 빈으로 등록되어 있지 않다는 에러가 뜨게 된다.
그니까 @Controller를 MemberController
위에 써주면 해결된다!
같은 맥락으로 MemberService
에는 @Service를, MemoryMemberRepository
에는 @Repository를 써줘야 한다.
마지막으로, MemberController
에서 MemberService
를 활용하고 있음을 확인할 수 있다.
비슷하게 MemberService
에서는 MemberRepository
를 활용하고 있다.
(MemberController -> MemberService -> MemberRepository)
이렇게 활용하고 있는 관계를 의존관계라고 하는데, 이 때 @Autowired를 꼭 써줘야 한다!
때문에 MemberController
와 MemberSerivce
의 생성자에 @Autowired라는 어노테이션을 달아주자.
최종적인 MemberController
의 코드는 다음과 같다.
@Controller, @Service, @Repository 모두 @Component에 속하는 케이스이며
이렇게 컴포넌트로 명시된 것들을 스프링이 찾아 빈으로 만들어 컨테이너에 등록하기 때문에
이를 컴포넌트 스캔이라고 한다.
자바 코드로 직접 스프링 빈 등록하기
위에서 MemberService
와 MemoryMemberRepository
에 등록한 어노테이션인
@Service, @Repository, @Autowired를 없애주자. (MemberController
는 건드리지 않는다)
그러면 MemberController
에서 생성자의 인자로 들어오는 MemberService
가 스프링 빈으로 등록되지 않아서
에러가 발생하게 된다. 때문에 스프링 빈으로 등록해주는 작업이 필요하다.
hello/hellospring/service
에 SpringConfig
라는 클래스를 만들고 다음과 같이 써주자.
MemberService
와 MemberRepository
를 스프링 빈으로 등록해기 위해 @Bean을 반드시 붙여야 한다!
참고로 MemberSerice
의 생성자의 인자로 MemberRepository
가 들어오기 때문에
리턴 시 return new MemberService(memberRepository())
로 써줘야 한다!
컴포넌트 스캔도 그렇고 스프링 빈 등록에서도 그렇고 생성자 주입 방식을 따랐는데,
의존성 주입(Dependency Injection: DI)을 하는 방법은 3가지 방법이 있다고 한다.
- 필드 주입 : 필드 앞에 @Autowired를 붙여서 연결하는 방식
- setter 주입 : setter를 활용해 연결하는 방식
- 생성자 주입 : 생성자의 특성을 활용해 연결하는 방식
어차피 Runtime에서 변경될 이유나 해당 사항이 없기 때문에 안정적인 생성자 주입을 추천한다고 한다.
컴포넌트 스캔 방식과 스프링 빈으로 등록하는 방식 중 어떤 것을 써야할까?
컴포넌트 스캔 방식은 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드에서 사용하고
스프링 빈 등록 방식은 구현 클래스를 변경해야하는 상황일 때 사용한다고 한다.
이전글에서 데이터 저장소가 등록되지 않은 상황을 가정하자고 했었다.
그러니까 MemberRepository
라는 인터페이스를 만들고 그 구현체인 MemoryMemberRepository
를 사용했는데
상황에 따라 MemberRepository
를 구현하지만 MemoryMemberRepository
가 아닌 다른 구현체를 활용해야 할 때
SpringConfig
에서 MemberRepository
에 리턴하는 내용을 다른 구현체로 바꿔치기해주면 된다!
컴포넌트 스캔 방식일 때는 이것저것 건드려줘야 하는데 반해 간단하게 수정할 수 있는 장점이 있다!
댓글남기기