회원 서비스가 실행되기 위해서 MemberController가 MemberService를 통해서 회원 가입하고
MemberService를 통해서 데이터(MemberRepository)를 조회할 수 있어야 한다.
이렇게 한 객체가 다른 객체를 사용할 때 의존성이 있다고 한다.
회원 서비스를 제대로 동작시키기 위해서 Controller와 Service에 대한 의존성을 주입해야 한다.
의존성 주입(Dependecy Injection, DI)
의존성 주입(DI)란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 다이나믹하게 주입하는 것이다.
DI의 장점은 유연성을 확보하고 결합도를 낮출 수 있게 해 준다.
스프링 빈(Spring Bean)
Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라고 부른다.
Member 의존관계 설정
Member Controller 생성
controller 패키지에 Member Controller를 생성한다.
package hello.hellospring.controller;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
}
기능은 아무것도 없지만, Spring이 실행될 때 Spring Container가 생성된다.
Container에 @Controller annotation이 있으면
@Controller가 있는 class (여기서 MemberController) 객체를 생성하여
Spring Container에 넣어두고 관리한다.
MemberController에서 MemberService를 써야 하는데
new를 써서 객체를 생성할 수 있지만
Spring이 관리하게 되면 Spring Container에 등록하여 Spring Container에서 받아와서 쓰도록 바꿔야 한다.
new로 객체를 새로 생성하면 MemberController 외에 다른 Controller들이 MemberService를 가져와 쓸 수 있을 것이다.
그런데 여러 객체를 생성하지 않고 하나만 생성하여 공용으로 쓰는 것이 더욱 옳은 방향이다.
그래서 Spring Container에 등록을 하고 쓰는 것이 좋다.
Spring Container에 하나만 등록이 되는데 이것을 통한 효과는 여러 가지가 있다.
Spring Container에 등록
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
생성자에 @Autowired라고 되어있으면 memberService를
Spring이 Spring Container에 있는 MemberService를 가져와서 연결시켜준다.
그런데 이대로 실행하면 에러가 발생한다.
Parameter 0 of constructor in hello.hellospring.controller.MemberController required a bean of type 'hello.hellospring.service.MemberService' that could not be found.
Controller는 Spring이 실행될 때 Spring Container에 등록이 된다.
그러면 @Autowired는 MemberService 객체를
Spring Container에서 가져와서 memberService에 연결시켜준다.
왜 MemberService를 찾을 수 없다는 에러가 발생할까?
MemberService는 순수한 자바 클래스로 Spring이 MemberService를 찾을 수 없다.
Spring이 MemberService를 찾을 수 있도록 Annotation을 넣어주어야 한다.
MemberService에 @Service Annotation을 넣어주면
Spring이 @Service를 인식하여 SpringContainer에 MemberService를 등록한다.
Repository에도 @Repository Annotation을 넣어서 Spring에서 찾아서 등록되게 한다.
Controller와 Service를 연결시켜주려면 @Autowired를 붙인 생성자를 작성한다.
MemberController가 생성될 때 Spring Bean(Spring IoC Container에서 관리하는 객체)에서 등록되어 있는 MemberService 객체를 가져와서 memberService에 넣어준다.
이것이 Dependency Injection이다. 의존 관계를 주입해주는 것.
컴포넌트 스캔
위와 같은 방식으로 의존성 주입을 한 것이 컴포넌트 스캔 방식이다.
- @Component Annotation이 있으면 Spring Bean으로 자동 등록된다.
- @Service @Controller, @Repository Annotation에 @Component Annotation이 포함되어 있다.
-> Spring Bean으로 자동 등록된 이유
@Component를 붙인다고 모두 Spring Bean으로 등록되는 것은 아니다.
기본적으로 컴포넌트 스캔은 해당 @SpringBootApplication이 있는 main 클래스부터
해당 패키지 하위 패키지를 모두 찾아서 Spring Bean으로 등록한다.
하위 패키지와 동일하거나 하위 패키지가 아닌 것들은 별도의 설정을 하지 않는 이상
컴포넌트 스캔 대상이 아니다.
스프링은 스프링 컨테이너 스프링 빈을 등록할 때, 기본적으로 싱글톤으로 등록한다. (유일하게 하나만 등록해서 공유한다.) 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다. 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.