[스프링부트 입문] 4. 자바 코드로 스프링 빈 직접 등록하기
현재 의존 관계는 위와 같다. 여기서 memberController만 @Autowired를 이용하고 memberService과 memberRepository는 자바 코드를 이용해 스프링 빈에 직접 등록해보려고 한다.
먼저 memberService와 memberRepository는 각각 아래와 같다.(메서드 생략)
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository){
this.memberRepository=memberRepository;
}
}
public class MemoryMemberRepository implements MemberRepository{
}
주목할만한 점은 MemberService의 생성자에서 memberRepository를 인자를 받는다는 점이다.
이제 두 클래스를 스프링 빈에 등록할건데 자바 코드로 직접 등록하기 위해서는 SpringConfig라는 파일을 사용한다. SpringConfig파일은 아래와 같이 작성한다.
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
이렇게 하면 처음 스프링이 실행될 때 이 SpringConfig파일을 보고 각 메서드를 실행해서 MemberService와 MemberRepository를 스프링 빈으로 등록해준다. MemberService는 MemberRepository를 생성자의 인자로 받으니까 이때 스프링 빈에서MemberRepository를 가져와 사용한다.
그리고 현재 MemberController는 @Controller 어노테이션이 붙어있으니 컴포넌트 스캔을 통해 스프링 빈에 등록된다.
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService){
this.memberService=memberService;
}
}
그리고 @Autowired를 보고 스프링 빈에 등록된 MemberService를 가져와서 등록한다.
예전에는 xml이라는 문서를 이용해 스프링빈을 등록했는데 요즘은 잘 사용하지 않는다고 한다. 또 방금은 생성자를 이용한 DI를 했는데 사실 필드 주입, setter 주입 방법도 있다. 우선 간단하게 살펴보도록 하자. 결론적으로는 생성자를 이용한 주입을 권장한다.
필드 주입
아래와 같이 의존성을 주입하는게 필드 주입이다. 이렇게 작성하면 코드가 간결하다는 장점이 있다. 하지만 의존성 주입을 위해 Spring Container가 필요하기 때문에 테스트가 어렵다. 객체를 직접 생성하면서 의존성을 주입하는 생성자 주입과 다르다.
@Controller
public class MemberController {
@Autowired
private MemberService memberService;
// @Autowired
// public MemberController(MemberService memberService){
// this.memberService=memberService;
// }
}
참고로 private임에도 불구하고 필드 주입이 가능한 이유는 Java의 Reflection API를 사용하면 접근 제한자를 무시하고 필드에 직접 접근할 수 있기 때문이다. Spring Framework는 이러한 Reflection API를 사용해 private으로 선언된 필드에도 의존성을 주입할 수 있다.
Setter 주입
setter주입은 setter클래스를 이용해 의존성을 주입하는 방법이다. 객체가 생성된 후에도 의존성을 변경할 수 있지만 그런 경우는 거의 없다. 또 보다시피 setMemberController메서드는 public인데 이 경우 setMemberController가 실수로 호출될 수도 있다.
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public void setMemberController(MemberService memberService){
this.memberService=memberService;
}
}
이러한 이유 때문에 스프링에서는 생성자를 이용한 주입을 권장한다. 또 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다고 한다.