
@ComponentScan 어노테이션을 사용하면, @Component 어노테이션이 붙은 클래스를 찾아서 Bean으로 등록한다.@Autowired 어노테이션을 사용하면, 해당 타입의 Bean을 찾아서 의존관계를 자동으로 주입한다.basePackages : String[]
basePackageClasses : Class<?>[]
includeFilters : Filter[]
excludeFilters : Filter[]
useDefaultFilters : boolean
true@Component, @Repository, @Service, @Controller, @Configuration 어노테이션을 스캔 대상으로 설정한다.lazyInit : boolean
false@Component 어노테이션을 가진 Bean을 생성할 때, Lazy Initialization을 사용할지 여부nameGenerator : BeanNameGenerator
DefaultBeanNameGeneratorAnnotationBeanNameGeneratorFullyQualifiedAnnotationBeanNameGeneratorpublic interface BeanNameGenerator {
    String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
scopeResolver : ScopeMetadataResolver
AnnotationScopeMetadataResolverJsr330ScopeMetadataResolverpublic interface ScopeMetadataResolver {
    ScopeMetadata resolveScopeMetadata(BeanDefinition definition);
}
scopedProxy : ScopedProxyMode
ScopedProxyMode.DEFAULTScopedProxyMode.NOScopedProxyMode.INTERFACES : 인터페이스를 사용하여 JDK dynamic Proxy를 생성한다.ScopedProxyMode.TARGET_CLASS : CGLIB 라이브러리를 사용하여 Proxy를 생성한다.lazyInit : boolean
false@Component 어노테이션을 가진 Bean을 생성할 때, Lazy Initialization을 사용할지 여부resourcePattern : String
**/*.classClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN@Component@Controller@Repository@Service@Configuration@Bean 어노테이션을 가진 메서드를 호출하여 Singleton Bean으로 등록한다.@ComponentScan(includeFilters = {...})@ComponentScan(excludeFilters = {...})@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
    FilterType type() default FilterType.ANNOTATION;
    @AliasFor("classes")
    Class<?>[] value() default {};
    @AliasFor("value")
    Class<?>[] classes() default {};
    String[] pattern() default {};
}
ANNOTATIONASSIGNABLE_TYPEASPECTJpattern을 사용하여 클래스를 찾는다.REGEXpattern을 사용하여 클래스를 찾는다.CUSTOMTypeFilter 인터페이스를 구현한 클래스를 사용하여 클래스를 찾는다.public enum FilterType {
    
	ANNOTATION,
  
	ASSIGNABLE_TYPE,
  
	ASPECTJ,
  
	REGEX,
  
	CUSTOM
}
public interface TypeFilter {
	boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException;
}
ConflictingBeanDefinitionException 예외 발생Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=truespring.main.allow-bean-definition-overriding=true 설정을 통해 오류를 해결할 수 있다.의존관계 주입에는 크게 4가지 방법이 있다.
@Autowired 어노테이션을 생략할 수 있다.@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
}
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}
dependencies {
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}
@Autowired(required = false) 로 설정할 경우@Component
public class OrderServiceImpl implements OrderService {
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;
    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    @Autowired
    public void setDiscountPolicy(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}
@SpringBootTest 처럼 Spring Container를 기반으로 테스트하는 경우, 사용할 수 있다.@Component
public class OrderServiceImpl implements OrderService {
    @Autowired
    private MemberRepository memberRepository;
    @Autowired
    private DiscountPolicy discountPolicy;
}
@Component
public class OrderServiceImpl implements OrderService {
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;
    @Autowired
    public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}
@Autowired(required = false)@Nullable : org.springframework.lang.Nullablenull이 주입된다.Optional<T>Optional.empty가 주입된다.NoUniqueBeanDefinitionException 예외 발생@Autowired 필드 명 매칭@Qualifier 사용@Primary 사용@Autowired
private DiscountPolicy rateDiscountPolicy;
@Qualifier 는 추가적인 구분자를 붙여준다.@Qualifier 어노테이션을 사용하여 추가적인 구분자를 붙여준다.@Autowired 어노테이션을 사용할 때, @Qualifier 어노테이션을 사용하여 구분자를 지정한다.@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {
    // ...
}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, 
                        @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
    this.memberRepository = memberRepository;
    this.discountPolicy = discountPolicy;
}
@Primary 어노테이션을 사용하여 우선권을 가지는 Bean을 설정한다.@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {
    // ...
}
@Component
public class FixDiscountPolicy implements DiscountPolicy {
    // ...
}
@Qualifier가@Primary보다 우선순위가 높다.
@Qualifier 끼리 매칭 @Primary 매칭List<T> : 타입의 모든 Bean을 주입받을 수 있다.Map<String, T> : 타입의 모든 Bean을 이름을 키로 조회할 수 있다.@Component
@RequiredArgsConstructor
public class DiscountService {
    private final Map<String, DiscountPolicy> policyMap;
    private final List<DiscountPolicy> policies;
    public int discount(Member member, int price, String discountCode) {
        DiscountPolicy discountPolicy = policyMap.get(discountCode);
        return discountPolicy.discount(member, price);
    }
}
@Component, @Controller, @Service, @Repository@Configuration, @Bean
Reference: 스프링-핵심-원리-기본편 (인프런)