@ComponentScan
μ΄λ, @Component
λ° Stereo Type(@Service, @Repository, @Controller)
μ΄ λΆμ¬λ ν΄λμ€λ€μ μλμΌλ‘ μ€μΊνμ¬ λΉμΌλ‘ λ±λ‘ν΄μ£Όλ μν μ νλ€.
λΉμΌλ‘ λ±λ‘ λ μ€λΉλ₯Ό λ§μΉ ν΄λμ€λ€μ μ€μΊνμ¬, λΉμΌλ‘ λ±λ‘ν΄μ£Όλ κ²μ΄λ€.
λΉμΌλ‘ λ±λ‘ λ μ€λΉλ, ν΄λμ€μ @Component
λ° Stereo Type(@Service, @Repository, @Controller)
μ λΆμ¬μ λΉμΌλ‘ λ±λ‘ λ μ€λΉλ₯Ό ν κ²μ΄λ€.
μ΄μ xml
νμΌμ <context:component-scan base-package="ν¨ν€μ§κ²½λ‘"/>
λ₯Ό μ΄μ©ν΄ μ§μ ν΄μ£Όμλ κ²μ javaνμΌμ μ΄μ©νμ¬ λΉμ μ€μΊνκΈ° μν΄ μ겨λ¬λ€.
μ΄λ€ μ λ
Έν
μ΄μ
μ μ€μΊν μ§ λλ νμ§ μμμ§ κ²°μ νλ Filter κΈ°λ₯
μ κ°μ§κ³ μλ€.
@ComponentScan
μμ μ€μν μ€μ μΌλ‘λ BasePackages
μ BasePackageClasses
κ° μλ€.
BasePackages
λ String
μΌλ‘ μ
λ ₯λ ν¨μΊμ§μ κ²½λ‘λ₯Ό μ€μΊνλ λ°©λ²μ΄λ€.
BasePackageClasses
λ μ λ¬λ ν΄λμ€μ μμΉλ₯Ό κΈ°μ€μΌλ‘ μ€μΊνλ λ°©λ²μ΄λ€.
BasePackageClasses
μ¬μ©μ λ μΆμ²νλ€.
StringBootλ₯Ό μ¬μ©νλ€λ©΄ μ°λ¦¬κ° λ°λ‘ μ€μ νμ§ μλ μ΄μ @ComponentScan
μ 보기 νλ€λ€.
κ·Έ μ΄μ λ @SpringBootApplication
μ΄ @ComponentScan
μ΄λ @Configuration
μ λ€κ³ μκΈ° λλ¬Έμ΄λ€.
@Component
: μ»΄ν¬λνΈ μ€μΊμμ μ¬μ©@Controller
: μ€νλ§ MVC 컨νΈλ‘€λ¬μμ μ¬μ©@Service
: μ€νλ§ λΉμ¦λμ€ λ‘μ§μμ μ¬μ©@Repository
: μ€νλ§ λ°μ΄ν° μ κ·Ό κ³μΈ΅μμ μ¬μ©@Configuration
: μ€νλ§ μ€μ μ 보μμ μ¬μ©β @Configuration
νμ±
ConfigurationClassParser
κ° @Configuration
ν΄λμ€λ₯Ό νμ±νλ€.
β‘ @ComponentScan
μ€μ νμ±
κ°λ°μλ basePackage
, basePackesClasses
, excludeFilters
, includeFilters
, lazyInit
, nameGenerator
, resourcePattern
, scopeProxy
λ± μ»΄ν¬λνΈλ€μ μ€μΊνκΈ° μν μ€μ μ μ μνλ€. ComponentScanAnnotationParse
κ° μ»΄ν¬λνΈ ν보λ₯Ό λͺ¨λ μ°Ύκ³ , μ€μΊνκΈ° μν΄ μ€μ μ νμ±νλ€.
β’ ν΄λμ€ λ‘λ©
base-package
μ€μ μ λ°νμΌλ‘ λͺ¨λ ν΄λμ€λ₯Ό λ‘λ©νλ€. (*.class)
ν΄λμ€λ‘λλ₯Ό μ΄μ©νμ¬ λͺ¨λ μμμ Resource μΈν°νμ΄μ€ ννλ‘ λΆλ¬μ¨λ€.
β£ λΉ μ μ μ€μ
ClassLoader
κ° λ‘λ©ν ν΄λμ€λ₯Ό BeanDefinition
μΌλ‘ μ μνλ€.
κ·Έλ¦¬κ³ beanName
μ key
κ°μΌλ‘ BeanDefinitionRegistry
μ λ±λ‘ν΄λλλ€.
μμ±ν λΉμ λν μ μ(λ©ν λ°μ΄ν°)λ€.
β€ λΉ μμ± & μ£Όμ
.
μ€μ ν λΉ μ μλ₯Ό λ°νμΌλ‘ κ°μ²΄λ₯Ό μμ±νκ³ , μ£Όμ
νλ€.
π‘ μ 리
Configuration ν΄λμ€
λ°μ λ Έν μ΄μ
μ μ¬μ©νλ μ€μ λ€μ νμ±νλ€.
basePackage
μ νμ ν΄λμ€λ€μ λΆλ¬μμComponent
ν보μΈμ§ νμΈ νBeanDefinition
(λΉ μμ±μ μν μ μ) μ λ§λ λ€.
μμ±λ λΉ μ μλ₯Ό λ°νμΌλ‘ λΉμ μμ±νκ³ μμ‘΄μ±μλ λΉλ€μ μ£Όμ νλ€.
@CompoenentScan
μ¬μ© λ°©λ²μ xmlνμΌμ μ€μ νλ λ°©λ²
κ³Ό μλ°νμΌμμμ μ€μ νλ λ°©λ²
μ΄ μλ€.
<context:component-scan base-package="com.rcod.lifelog"/>
xml νμΌ
μ μ€μ νκ³ , base-package
μ μ μ΄μ£Όλ©΄ base-package
κΈ°μ€μΌλ‘ ν΄λμ€λ€μ μ€μΊνμ¬ λΉμΌλ‘ λ±λ‘νλ€. base-package
μ μ¬λ¬κ°μ ν¨ν€μ§λ₯Ό μΈ μ μλ€.
<context:component-scan base-package="com.rcod.lifelog, com.rcod.example"/>
μμ κ°μ΄ μ€μ νλ©΄, base package
νμμ @Controll
, @Service
, @Repository
, @Component
ν΄λμ€κ° λͺ¨λ λΉμΌλ‘ λ±λ‘λλ―λ‘, νΉμ ν κ°μ²΄λ§ λΉμΌλ‘ λ±λ‘νμ¬ μ¬μ©νκ³ μΆλ€λ©΄ include-filter
λλ exclude-filter
λ₯Ό ν΅ν΄ μ€μ ν μ μλ€.
π include-filter
<context:component-scan base-package="com.rcod.lifelog" use-default="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
use-default="false"
λ κΈ°λ³Έ μ λ
Έν
μ΄μ
@Controller
, @Component
λ±μ μ€μΊνμ§ μλ λ€λ κ²μ΄λ€.
κΈ°λ³Έ μ λ
Έν
μ΄μ
μ μ€μΊνμ§ μλλ€κ³ μ€μ νκ³ , include-filter
μ ν΅ν΄μ νΉμ μ λ
Έν
μ΄μ
λ§ μ€μΊν μ μλ€.
π exclude-filter
<context:component-scan base-package="com.rcod.lifelog">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
@Controller
λ₯Ό μ μΈνκ³ μΆλ€λ©΄ exclude-filter
λ₯Ό μ¬μ©νμ¬ org.springframework.stereotype.Controller
λ₯Ό λͺ
μνλ€.
π‘ λμ μμ
β@Comfiguration
,@ConponentScan
μ§μ
β‘ κ° ν΄λμ€κ° μ»΄ν¬λνΈ μ€μΊμ λμμ΄ λλλ‘@Component
μ§μ
β’@Component
λ‘ μ§μ λ ν΄λμ€μμ μμ±μ λ©μλμ@Autowired
μ μ§μ νμ¬ μμ‘΄κ΄κ³ μ£Όμ
β @Comfiguration
, @ConponentScan
μ§μ
package hello.core;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class AutoAppConfig {}
@Configuration
μ μ΄μ©νμ¬ λΉ μ€μ νμΌ(XML νμΌμ λ체νλ)μμ μλ €μ€λ€.
@ComponentScan
μ μ΄μ©ν΄ λΉμΌλ‘ λ±λ‘λκΈ° μν μ λ
Έν
μ΄μ
μ΄ λΆμ¬λ ν΄λμ€λ€μ μλμΌλ‘ IoC컨ν
μ΄λμ λ±λ‘νλλ‘ νλ€.
@ComponentScan
μ μ¬μ©νλ©΄ @Configuration
μ΄ λΆμ μ€μ μ 보λ μλμΌλ‘ μ€νλ§ IoC 컨ν
μ΄λμ λΉμΌλ‘ λ±λ‘λλ€.
@Configuration
μ μμ€μ½λμ @Conponent
κ° ν¬ν¨λμ΄ μκΈ° λλ¬Έμ΄λ€.
β‘ κ° ν΄λμ€κ° μ»΄ν¬λνΈ μ€μΊμ λμμ΄ λλλ‘ @Component
μ§μ
package hello.core.member;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long, Member> store = new HashMap<>();
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
@ComponentScan
μ @Component
κ° λΆμ λͺ¨λ ν΄λμ€λ₯Ό μ€νλ§ λΉμΌλ‘ λ±λ‘νλ€.
μ΄ λ μ€νλ§ λΉμ κΈ°λ³Έ μ΄λ¦μ ν΄λμ€ λͺ
μ μ¬μ©νλ 맨 μκΈμλ§ μλ¬Έμλ₯Ό μ¬μ©νλ€.
λΉ μ΄λ¦μ μ§μ μ§μ νκ³ μΆμ λλ @Component("μνλμ΄λ¦")
μΌλ‘ μμ±νλ€.
β’ @Component
λ‘ μ§μ λ ν΄λμ€μμ μμ±μ λ©μλμ @Autowired
μ μ§μ νμ¬ μμ‘΄κ΄κ³ μ£Όμ
package hello.core.member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
μμ±μμ @Autowired
λ₯Ό μ§μ νλ©΄, μ€νλ§ μ»¨ν
μ΄λκ° μλμΌλ‘ ν΄λΉ μ€νλ§ λΉμ μ°Ύμμ μ£Όμ
νλ€.
μ΄ λ κΈ°λ³Έ μ‘°ν μ λ΅μ νμ
μ΄ κ°μ λΉμ μ°Ύμμ μ£Όμ
νλ€.
getBean(MemberRepository.class)
μ λμΌνλ€.
μμ±μμ νλΌλ―Έν°κ° λ§μλ λ€ μ°Ύμμ μλμΌλ‘ μ£Όμ νλ€.
π @ComponentScan λ²μ
basePackages
@Configuration
@ComponentScan(basePackages = "com.kureungkureung.spring")
public class ApplicationConfig {}
basePackages
μ κ²½μ° κ΄νΈμμ μ§μ ν¨ν€μ§ κ²½λ‘λ₯Ό μ μ΄μ£Όμ΄ μ€μΊν μμΉλ₯Ό μ νλ€.
basePackages = {"hello.core", "hello.service"}
μ²λΌ μ¬λ¬ μμ μμΉλ₯Ό μ§μ ν μλ μλ€.
basePackages
λ Typesafeνμ§ μμκΈ° λλ¬Έμ μ‘°κΈλ§ μ² μκ° μλͺ»λλλΌλ μ€μΊμ λͺ»νλ μ€λ₯κ° λνλ μ μλ€.
basePackagesClasses
@Configuration
@ComponentScan(basePackageClasses = Application.class)
public class ApplicationConfig {}
basePackageClasses
μ κ²½μ°μλ κ΄νΈμμ μ ν ν΄λμ€κ° μμΉν κ³³μμλΆν° λͺ¨λ μ λ
Έν
μ΄μ
μ΄ λΆμ¬λ ν΄λμ€λ₯Ό λΉμΌλ‘ λ±λ‘νλ€.
basePackageClasses
λ₯Ό μ§μ νμ§ μμΌλ©΄ @ComponentScan
μ΄ λΆμ μ€μ μ 보 ν΄λμ€μ ν¨ν€μ§κ° μμ μμΉκ° λλ€.
basePackagesClasses
λ ν΄λμ€λ₯Ό ν΅ν΄ κΈ°μ
νκΈ° λλ¬Έμ ν¨μ¬ Typesafeν λ°©λ²μ΄λ€.
π§· κΆμ₯ λ°©λ²
ν¨ν€μ§ μμΉλ₯Ό μ§μ νμ§ μκ³ , μ€μ μ 보 ν΄λμ€μ μμΉλ₯Ό νλ‘μ νΈ μ΅μλ¨μ λλ κ²μ΄λ€.
μ΅κ·Ό μ€νλ§ λΆνΈλ μ΄ λ°©λ²μ κΈ°λ³ΈμΌλ‘ μ 곡νλ€.
ex) νλ‘μ νΈ κ΅¬μ‘°
com.hello
com.hello.service
com.hello.repository
μ΄λ κ² μλ€κ³ κ°μ ν λ,
com.hello
μ νλ‘μ νΈ μμ 루νΈμΈ AppConfigκ°μ λ©μΈ μ€μ μ 보λ₯Ό λκ³ @ComponentScan
μ λΆμ΄κ³ basePackages
μ§μ μ μλ΅νλ€.μ°Έκ³ λ‘ μ€νλ§ λΆνΈλ₯Ό μ¬μ©νλ©΄ μ€νλ§ λΆνΈμ λν μμ μ λ³΄μΈ @SpringBootApplication
μ νλ‘μ νΈ μμ λ£¨νΈ μμΉμ λ¬μΌνλ€.
π νν°
includeFilters
μ»΄ν¬λνΈ μ€μΊ λμμ μΆκ°λ‘ μ§μ νλ€.
@Component
λ₯Ό μ¨λ μΆ©λΆνκΈ° λλ¬Έμ includeFilters
λ₯Ό μ¬μ©ν μΌμ κ±°μ μλ€.
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent { }
package hello.core.scan.filter;
@MyIncludeComponent
public class BeanA { }
π @Target
μ λ
Έν
μ΄μ
μ΄ μ μ©ν μμΉλ₯Ό μ ννλ€.
μ λ
Έν
μ΄μ
μ΄ μμ±λ μ μλ μμΉλ₯Ό μ§μ νλ€.
ElementType.PACKAGE
: ν¨ν€μ§ μ μΈElementType.TYPE
: νμ
μ μΈElementType.ANNOTATION_TYPE
: μ λ
Έν
μ΄μ
νμ
μ μΈElementType.CONSTRUCTOR
: μμ±μ μ μΈElementType.FIELD
: λ©€λ² λ³μ μ μΈElementType.LOCAL_VARIABLE
: μ§μ λ³μ μ μΈElementType.METHOD
: λ©μλ μ μΈElementType.PARAMETER
: λ©μλμ νλΌλ―Έν°λ‘ μ μΈλ κ°μ²΄μμλ§ μ¬μ© κ°λ₯ElementType.TYPE_PARAMETER
: μ λ¬μΈμ νμ
μ μΈElementType.TYPE_USE
: νμ
μ μΈπ @Retention
ν΄λΉ μ λ
Έν
μ΄μ
μ΄ μΈμ κΉμ§ μ μ§ν μ§ μλ €μ£Όλ μ λ
Έν
μ΄μ
μ΄λ€.
μκΈ° μμ μ΄ μ΄λ μμ κΉμ§ μ ν¨νμ§λ₯Ό λͺ
μν΄μ€μΌνλ€.
RetentionPolicy.SOURCE
: μ»΄νμΌ μ κΉμ§λ§ μ ν¨. (μ»΄νμΌ μ΄νμλ μ¬λΌμ§)RetentionPolicy.CLASS
: μ»΄νμΌλ¬κ° ν΄λμ€λ₯Ό μ°Έμ‘°ν λκΉμ§ μ ν¨.RetentionPolicy.RUNTIME
: μ»΄νμΌ μ΄νμλ JVMμ μν΄ κ³μ μ°Έμ‘°κ° κ°λ₯. (리νλ μ
μ¬μ©)π @Documented
λ©ν λ°μ΄ν° μ λ
Έν
μ΄μ
μ΄λ€.
λ¬Έμμ μ λ
Έν
μ΄μ
μ μ λ³΄κ° ννλλ€.
μ λ
Έν
μ΄μ
μ μ μν λ, @Documented
ννλ‘ μ μ©νμ¬, ν΄λΉ μ λ
Έν
μ΄μ
μ μ¬μ©νλ ν΄λμ€κ° javadoc
κ³Ό κ°μ λ¬Έμν λ λ, ν΄λΉ μ λ
Έν
μ΄μ
μ΄ μ μ© λμμμ λͺ
μνλλ‘ νλ€.
excludeFilters
μ»΄ν¬λνΈ μ€μΊμμ μ μΈν λμμ μ§μ νλ€.
excludeFilters
λ μ¬λ¬κ°μ§ μ΄μ λ‘ κ°νΉ μ¬μ©ν λκ° μμ§λ§ λ§μ§λ μλ€.
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent { }
package hello.core.scan.filter;
@MyExcludeComponent
public class BeanB { }
μ€νλ§ λΆνΈλ μ»΄ν¬λνΈ μ€μΊμ κΈ°λ³ΈμΌλ‘ μ 곡νλ€. μ΅μ μ λ³κ²½νλ©΄μ μ¬μ©νκΈ° 보λ€λ μ€νλ§μ κΈ°λ³Έ μ€μ μ μ΅λν λ§μΆμ΄ μ¬μ©νλκ²μ΄ μ’λ€.
@ComponentScan(
includeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyIncludeComponent.class),
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class)
)
includeFilters
μ MyIncludeConponent
μ λ
Έν
μ΄μ
μ μΆκ°ν΄μ BeanA
κ° μ€νλ§ λΉμ λ±λ‘λλ€.
excludeFilters
μ MyExcludeComponent
μ λ
Έν
μ΄μ
μ μΆκ°ν΄μ BeanB
λ μ€νλ§ λΉμ λ±λ‘λμ§ μλλ€.
μ°Έκ³ μλ£
μ€νλ§ ν΅μ¬μ리 - κΈ°λ³ΈνΈ (μΈνλ° - κΉμν)