@ComponentScan & @Autowired에 대하여
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy(){
return new FixDiscountPolicy();
}
}
위의 코드처럼 수동으로 스프링 빈을 등록할 수 있지만 빈의 개수가 많아지면 여러모로 불편한 점이 많아진다.
하지만 스프링은 스캔해서 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다.
@Configuration
@ComponentScan
public class AutoAppConfig {
}
새로운 설정 파일을 생성하였고, 다음과 같이 @ComponentScan을 써주면 컴포넌트 스캔이 사용된다.
컴포넌트 스캔은 @Component가 있는 클래스를 스캔해서 스프링 빈으로 등록한다.
따라서 기존 설정파일이었던 AppConfig에서 스프링 빈으로 등록해야 하는 클래스에 @Component를 작성해야한다.
(여기서는 MemverServiceImpl, OrderServiceImpl, MemoryMemberRepository, FixDiscountPolicy)
@Component
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
...
...
}
그리고 AppConfig에서 직접 명시하였던 의존관계 정보가 없기 때문에 클래스의 생성자에 @Autowired를 작성해주어야 한다.
이렇게 작성하면 의존관계가 자동으로 주입된다.
@Component
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
...
...
}
ComponentScan과 Autowired는 어떤 방식으로 동작될까?
- @ComponentScan
- @Component가 붙은 모든 클래스를 스캔 & 스프링 빈으로 등록
- 해당 빈의 이름은 클래스 명을 사용하고 맨 앞글자를 소문자로 사용(MemberServiceImpl → memberServiceImpl)
- 빈의 이름을 직접 지정하려면 다음과 같이 사용. @Component(”빈 이름")
- @Autowired
- 생성자에 @Autowired가 있다면 스프링 컨테이너가 자동으로 빈을 주입한다.
- 같은 타입의 빈을 찾아서 주입 (같은 타입이 여러개거나 없으면 오류가 난다.)
ComponentScan의 탐색 위치기본 스캔 대상
@Configuration
@ComponentScan(
basePackages = "hello.core.member"
)
public class AutoAppConfig {
}
컴포넌트 스캔의 스캔 위치를 별도로 지정할 수 있다. 지정하지 않으면 @ComponentScan이 있는 클래스의 패키지를 기본 위치로 설정한다.
- 위와같이 basePackages에 원하는 시작 위치를 입력하면 해당 위치부터 하위 패키지를 스캔한다.
- basePackages={”hello.core.order”, “hello.core.member”}처럼 여러 위치를 지정할 수 있다.
- basePackageClasses
- 지정한 클래스의 패키지를 스캔한다.
하지만 이렇게 일일히 별도로 지정하기 보다는 프로젝트 파일의 최상단에 두는것을 권장하신다고 한다.
위 사진의 프로젝트 구조에서는 hello.core가 되겠다.
스프링 부트를 사용하면 @SpringBootApplication을 프로젝트 파일의 최상단에 위치시키는 것이 관례인데 @Component을 포함하고 있기 때문이다.
ComponentScan의 기본 스캔 대상
컴포넌트 스캔은 @Component를 포함해서 여러가지를 스캔한다.
- @Component : 컴포넌트 스캔에서 사용
- @Controller : 스프링 MVC 컨트롤러에서 사용
- @Service : 스프링 데이터 접근 계층에서 사용
- @Repository : 스프링 데이터 접근 계층에서 사용
- @Configuration : 스프링 설정 정보에서 사용
왜냐하면 해당 애노테이션들이 @Component를 포함하고 있기 때문이다.