[Spring Boot] spring Bean과 의존관계 DI
(이전 글과 이어집니다.)
먼저 서비스를 동작시키기 위해서 촉발할 Controller가 필요하다.
@Controller public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
생성자에 @Autowired가 있으면 스프링이 객체를 만들고 컨테이너에 넣어둔다. 그렇게 되면 생성자 호출시 컨테이너에 등록되어 있는 서비스 객체를 바로 주입한다. 이것을 의존성 주입 DI(Dependency Injection) 이라고 한다.
근데 문제는 이렇게만 하면 기존의 Service와 연결 될까? 그렇지 않다.
그 이유는 역으로 생각했을 때 당연히 memberService가 스프링 빈으로 등록되어 있지 않기 때문이다!
그럼 memberService를 스프링 빈에 등록해보자.
스프링 빈에 등록하는 방법은 2가지가 있다.
1. @Component 어노테이션이 있으면 자동으로 스프링 빈에 등록된다. 이를 포함하는 @Controller @Service @Repository도 마찬가지이다.
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
// -------------------------------------------------------------
@Repository
public class MemoryMemberRepository implements MemberRepository {}
@Autowired만 있으면 객체 생성시(생성자 호출 시)에 컨테이너에서 해당 객체(스프링 빈)을 찾아서 주입한다. 이때는 생성자가 1개만 있으면 Autowired를 생략할 수 있다. 이때 스프링 빈에 등록할 때는 싱글톤으로 등록한다.
2. 코드를 통해 직접 스프링 빈에 등록한다. @Service 어노테이션을 붙이고 @Repository 어노테이션을 붙이면 된다.
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이렇게 @Configuration 어노테이션을 달고 @Bean을 통해서 직접 생성하면 된다.
추가로 DI에는 필드 주입, setter주입, 생성자 주입이 있는데 필드 주입은 나중에 교체의 용이성이 떨어지고 setter의 경우에는 함부로 건드릴 일이 생길 수 있어서 생성자 주입을 사용하면 제일 옳은 방법이겠다.
또한 @Autowired를 통한 DI는 스프링 빈으로 등록한게 아니고 내가 직접 생성한 (new 를 통해) 객체에 대해서는 당연히 동작하지 않는다.