회원 컨트롤러가 회원서비스와 리포지토리를 사용할 수 있게 의존관계를 준비해보자
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
@Controller
: 컨트롤러를 스프링 빈으로 등록
@Autowired
: 생성자에 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이것을 의존성 주입이라고 한다.
컴포넌트 스캔 원리
Component
에노테이션 이 있으면 스프링빈으로 자동 등록한다.Controller
가 스프링빈으로 자동으로 등록된 이유도 컴포넌트 스캔 때문이다.Component
를 포함하는 다음 에노테이션도 스프링 빈으로 자동 등록된다.
@Controller
@Service
@Repository
MemberService
를 스프링 빈으로 등록해주지 않아 오류가 난다
@Service
public class MemberService {
private final MemoryMemberRepository memberRepository ;
@Autowired
public MemberService(MemoryMemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
...
}
생성자에
@Autowired
를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아 주입한다.
@Repository
public class MemoryMemberRepository implements MemberRepository{}
스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다 (유일하게 하나만 등록)
따라서 같은 스프링 빈이면 모두 같은 인스턴스.
@service
,@Repository
, @Autowired
를 제거하고 진행한다.
/java/hello.springgood/SpringConfig
package hello.springgood;
import hello.springgood.repository.MemoryMemberRepository;
import hello.springgood.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemoryMemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
Di에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있지만,
동적으로 의존관계가 변하는 일이 없기 때문에 생성자 주입으로 사용한다.
또한 웬만하면 컴포넌트 스캔을 사용하지만, 정형화 되지 않거나 상황에 따라 구현 클래스를 변경해야 할때는 스프링 빈으로 등록한다 .
@Autowired
를 통한 DI는 스프링이 관리하는 객체에서만 동작한다.