지금까지는 스프링 빈 등록시, @Bean, <bean> 으로 설정 정보 등록함.
-> 문제 : 스프링 빈 수 늘어날수록 할 일 너무 많아짐.
-> 해결 : 설정정보 없이 자동으로 빈 등록하는 컴포넌트 스캔 기능 제공.
@Configuration
@ComponentScan(
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class))
public class AutoAppConfig {
}
@ComponentScan 붙여주면 됨.@Bean등록한 클래스 없음.스캔 대상 : @Component 붙은 클래스
@Component
public class MemoryMemberRepository implements MemberRepository {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
설정정보 작성 없어져 편해짐. 근데 의존관계 명시까지 없어짐.
-> 의존관계 주입 시켜주자.
-> 생성자에 @Autowired
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}


@Autowired 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈 찾아서 주입.A. 실제로 @Autowired 없이도 의존관계 주입됨. 스프링 4.3 이후로 가능해졌음. 대신 생성자가 하나만 있을 경우에만 가능. 생성자가 두 개 이상일시, @Autowired 붙은 생성자만 의존관계 주입됨. ( 실무에서는 생성자를 두 개 이상 쓸 일 잘 없긴 함 )
모든 자바클래스 컴포넌트 스캔 하려면 시간 오래걸림. 꼭 필요한 위치부터 탐색하도록 시작 위치 지정 가능.
@ComponentScan(
basePackages = "hello.core",
}
basePackages: 탐색할 패키지 시작 위치 지정. 이 패키지 포함 하위 패키지 탐색함.패키지 위치 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것.
스프링 부트도 이 방법을 기본으로 제공함.
@SpringBootApplication 프로젝트 위치에 두는 관례. ( 이 설정정보 안에 @ComponentScan 들어있음 )@Component 뿐만 아니라 해당 것들도 스캔 대상.
-> @Controller, @Service, @Repository, @Configuration
@Component
public @interface Controller {
}
@Component
public @interface Service {
}
@Component
public @interface Configuration {
}
-> 소스코드 확인시, @Component 포함 확인
가능.
includeFilters : 컴포넌트 스캔 대상을 추가로 지정excludeFilters : 컴포넌트 스캔에서 제외할 대상 지정@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {}
@MyIncludeComponent
public class BeanA {}
@MyExcludeComponent
public class BeanB {}
@Configuration
@ComponentScan(
includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyInlcudeComponent.class),
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
)
public class AppConfig {}
컴포넌트 스캔에서 같은 빈 이름 등록하면 어떻게 될까.
ConflictingBeanDefinitionException 예외 발생@Component
public class MemoryMemberRepository implements MemberRepository {}
@Configuration
@ComponentScan(
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class)
)
public class AutoAppConfig {
@Bean(name = "memoryMemberRepository")
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
의도한 행동이라면 괜챃지만, 보통 설정 꼬여서 상황 발생함. -> 정말 잡기 어려운 버그 발생.
-> 최근 스프링 부트에서는 오류 발생하도록 바뀜.