아래와 같이 클래스에 @Configuration, 메서드에 @Bean을 붙여 수동으로 스프링 빈으로 등록하고 의존 관계를 설정해 줄 수 있지만 등록해야 할 Bean이 많아질 경우 번거로움
ComponentScan을 활용하여 이 문제를 해결!
ComponentScan 이란?
컴포넌트 스캔이란 스프링이 스프링 빈(Bean)으로 등록될 준비가 된 클래스들을 스캔하여 자동으로 빈(Bean)으로 등록해주는 과정을 말한다.
컴포넌트 스캔을 사용하려면 설정 정보 클래스에 @ComponentScan 어노테이션을 붙여 사용한다.
ComponentScan의 범위
이 때 컴포넌트 스캔의 범위는 설정 정보 클래스 패키지를 포함한 모든 하위 패키지가 된다.
ComponentScan의 기본 스캔 대상
→ @Controller, @Service, @Repository, @Configuration은 @Component를 포함하고 있음
ComponentScan의 대상이 될뿐더러 추가 기능을 수행하고 어떤 역할인지 나타내준다!
ComponentScan 범위 지정1
basePackages를 활용하여 범위를 직접 지정할 수 있다. 이 때는 hello.core 패키지와 그 하위 패키지를 탐색한다.
ComponentScan 범위 지정2
includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다
권장 방법 : 패키지 위치 지정 x, 설정 정보 클래스의 위치를 프로젝트 최상단에 둔다!!
빈 수동 등록은 @Bean을 붙이고 직접 의존 관계를 명시해줬다. 하지만 빈 자동 등록에서는 @Autowired로 의존 관계를 주입해준다.
의존 관계 주입 방법은 다음과 같은 방법이 있다.
1. ⭐⭐생성자 주입(빈 등록 + 의존관계 주입 동시)
@Component
public class MemberService{
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository
}
}
2. ⭐수정자 주입(setter 주입)
@Component
public class MemberService{
private final MemberRepository memberRepository;
@Autowired
public void setMemberRepository(MemberRepository memberRepository){
this.memberRepository = memberRepository
}
}
3. ❌필드 주입
@Component
public class MemberService{
@Autowired
private final MemberRepository memberRepository;
}
4. ❌일반 메서드 주입
@Component
public class MemberService{
private final MemberRepository memberRepository;
@Autowired
public void init(MemberRepository memberRepository){
this.memberRepository = memberRepository
}
}
결론
항상 생성자 주입을 사용하고 가끔 옵션이 필요한 경우 수정자 주입을 선택
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy;
}
}
다음과 같은 코드를 롬복을 사용해서 간단하게 해보자
간략화 버전1
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy;
}
}
간략화 버전2
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
즉 필드에 final을 붙이고 @RequiredArgsConstructor을 사용하자!
업무 로직 빈(자동) : Controller, Service, Repository 같이 유사한 패턴의 경우 자동 빈 등록
기술 지원 빈(수동) : 기술적 문제나, AOP(공통 관심사)처리, 데이터베이스 연결 등 → 설정 정보들을 한번에 관리하므로 오류 찾기 쉽고 유지 보수 용이
@Configuration
public class DiscountPolicyConfig {
@Bean
public DiscountPolicy rateDiscountPolicy() {
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy() {
return new FixDiscountPolicy();
}
}
DiscountPolicy처럼 다형성을 활용하는 비즈니스 로직은 수동 등록 고민! → 한 눈에 파악하기 위함