λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Spring/Spring Internal

Spring @ComponentScan λ™μž‘ κ³Όμ •

by 주발2 2023. 12. 9.
λ°˜μ‘ν˜•

Springμ—μ„œ ν΄λž˜μŠ€μ— @Configuration, @RestController, @Service λ“±μ˜ μ–΄λ…Έν…Œμ΄μ…˜μ„ μ„ μ–Έν•˜λ©΄ μŠ€ν”„λ§μ€ ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜λ“€μ„ μŠ€μΊ”ν•΄μ„œ 빈으둜 등둝을 ν•΄μ£ΌλŠ”λ°μš”, μ΄λŸ¬ν•œ 역할을 ν•˜λŠ” 것이 @ComponentScan μ–΄λ…Έν…Œμ΄μ…˜ μž…λ‹ˆλ‹€.

@ComponentScan 은 단어 κ·ΈλŒ€λ‘œ @Component μ–΄λ…Έν…Œμ΄μ…˜μ΄ 뢙은 ν΄λž˜μŠ€λ“€μ„ μŠ€μΊ”ν•˜μ—¬ μŠ€ν”„λ§ 빈으둜 λ“±λ‘ν•˜λŠ”λ°, μœ„μ— μ–ΈκΈ‰λœ μ–΄λ…Έν…Œμ΄μ…˜λ“€μ€ λͺ¨λ‘ 내뢀에 @Component μ–΄λ…Έν…Œμ΄μ…˜μ„ 가지고 μžˆμŠ΅λ‹ˆλ‹€.

 

@Service

 

@Configuration

 

μœ„μ™€ 같은 μ–΄λ…Έν…Œμ΄μ…˜λ“€μ„ μ„€μ •ν•˜λ©΄ μŠ€ν”„λ§μ—μ„œλŠ” μ–΄λ–»κ²Œ μ»΄ν¬λ„ŒνŠΈλ“€μ„ μŠ€μΊ”ν•˜κ³ , μŠ€ν”„λ§ 빈으둜 λ“±λ‘ν•˜λŠ”μ§€ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

 

 

@ComponentScan

ComponentScan

ComponentScan μ–΄λ…Έν…Œμ΄μ…˜μ— μ‘΄μž¬ν•˜λŠ” μ£Όμ„μœΌλ‘œ, λŒ€λž΅μ μΈ μ˜λ―ΈλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

@Configuration ν΄λž˜μŠ€λ“€κ³Ό ν•¨κ»˜ μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ”μ„ κ΅¬μ„±ν•˜λ©°, 
basePackageClasses ν˜Ήμ€ basePackages 쀑 ν•˜λ‚˜λ₯Ό μ§€μ •ν•˜μ—¬ μŠ€μΊ”ν•  ꡬ체적인 νŒ¨ν‚€μ§€λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.
λ§Œμ•½ ꡬ체적인 νŒ¨ν‚€μ§€κ°€ μ •μ˜λ˜μ§€ μ•Šμ•˜μ„ 경우, 이 μ–΄λ…Έν…Œμ΄μ…˜μ΄ μ •μ˜λœ 클래슀의 νŒ¨ν‚€μ§€λ‘œλΆ€ν„° μŠ€μΊ”μ΄ μˆ˜ν–‰λ©λ‹ˆλ‹€.
...

 

@ComponentScan μ–΄λ…Έν…Œμ΄μ…˜μ€ @SpringBootApplication μ–΄λ…Έν…Œμ΄μ…˜μ— μ‘΄μž¬ν•˜λŠ”λ°μš”, κ·Έλ ‡κΈ° λ•Œλ¬Έμ— λ”°λ‘œ μ„€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ main() λ©”μ„œλ“œκ°€ μ‘΄μž¬ν•˜λŠ” νŒ¨ν‚€μ§€λΆ€ν„° μŠ€μΊ”μ„ ν•˜κ²Œ λ©λ‹ˆλ‹€.

μŠ€ν”„λ§μ΄ μ»΄ν¬λ„ŒνŠΈλ“€μ„ μ–΄λŠ νŒ¨ν‚€μ§€μ—μ„œ μŠ€μΊ”ν• μ§€λŠ” ComponentScanAnnotationParser ν΄λž˜μŠ€μ—μ„œ @ComponentScan μ–΄λ…Έν…Œμ΄μ…˜μ„ νŒŒμ‹±ν•˜μ—¬ μ •μ˜ν•©λ‹ˆλ‹€.

 

 

 

ComponentScanAnnotationParser

ν•΄λ‹Ή ν΄λž˜μŠ€λŠ” 클래슀λͺ… κ·ΈλŒ€λ‘œ @ComponentScan μ–΄λ…Έν…Œμ΄μ…˜μ„ νŒŒμ‹±ν•˜λŠ” ν΄λž˜μŠ€μž…λ‹ˆλ‹€.

 

@ComponentScan μ–΄λ…Έν…Œμ΄μ…˜μ— μ‘΄μž¬ν•˜λŠ” λ©”μ„œλ“œλ“€μž…λ‹ˆλ‹€.

  • value(): basePackages의 alias
  • basePackages(): μ–΄λ…Έν…Œμ΄μ…˜ μ»΄ν¬λ„ŒνŠΈλ₯Ό μŠ€μΊ”ν•˜λŠ” κΈ°λ³Έ νŒ¨ν‚€μ§€
  • basePackageClasses(): basePackages()의 Type-safe λŒ€μ•ˆμœΌλ‘œ, μ§€μ •λœ 각 클래슀의 νŒ¨ν‚€μ§€λ₯Ό μŠ€μΊ”
  • nameGenerator(): μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ—μ„œ νƒμ§€λœ μ»΄ν¬λ„ŒνŠΈλ“€μ˜ 이름을 μ§€μ •ν•˜λŠ” 데 μ‚¬μš© (BeanNameGenerator)
  • scopeResolver(): μ»΄ν¬λ„ŒνŠΈμ˜ Scope λ²”μœ„ 확인
  • scopeProxy(): μ»΄ν¬λ„ŒνŠΈμ˜ ν”„λ‘μ‹œκ°€ μƒμ„±λ˜μ–΄μ•Ό ν•˜λŠ”μ§€ κ²°μ •
  • resourcePattern(): μ»΄ν¬λ„ŒνŠΈμ— μ ν•©ν•œ 클래슀 파일 μ œμ–΄ (보닀 μœ μ—°ν•œ 접근을 μœ„ν•΄ includeFilters, excludeFilters κ³ λ €)
  • useDefaultFilters(): @Component, @Repository, @Service, @Controller μ–΄λ…Έν…Œμ΄μ…˜μ΄ 달린 ν΄λž˜μŠ€λ“€μ— λŒ€ν•΄ μžλ™μœΌλ‘œ μŠ€μΊ”ν• μ§€ ν™œμ„±ν™” μ—¬λΆ€ (default = true)
  • includeFilters(): μ»΄ν¬λ„ŒνŠΈ μŠ€μΊλ‹μ— μ ν•©ν•œ νƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ 지정 (νŠΉμ • 쑰건을 λ§Œμ‘±ν•˜λŠ” 클래슀만 μŠ€μΊ”)
  • excludeFilters(): μ»΄ν¬λ„ŒνŠΈ μŠ€μΊλ‹μ— μ ν•©ν•˜μ§€ μ•Šμ€ νƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ 지정 (includeFilters 와 μ‚¬μš©λ²• 동일)

 

ComponentScanAnnotationParser.parse()

parse() λ©”μ„œλ“œλ₯Ό 톡해 @ComponentScan μ–΄λ…Έν…Œμ΄μ…˜μ— μ‘΄μž¬ν•˜λŠ” λ©”μ„œλ“œλ“€μ„ νŒŒμ‹±ν•©λ‹ˆλ‹€.

 

 

@SpringBootApplication μ–΄λ…Έν…Œμ΄μ…˜ 내에 μ‘΄μž¬ν•˜λŠ” @ComponentScan은 기본적으둜 basePackage, basePackageClasses 등에 λŒ€ν•΄ λ”°λ‘œ μ„€μ •ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— @SpringBootApplication μ–΄λ…Έν…Œμ΄μ…˜μ΄ μ‘΄μž¬ν•˜λŠ” νŒ¨ν‚€μ§€λ₯Ό basePackages 둜 μ„€μ •ν•©λ‹ˆλ‹€.

 

μœ„ @ComponentScan 의 νŒŒμ‹±μ΄ λλ‚˜λ©΄, scanner(ClassPathBeanDefinitionScanner) 둜 μ»΄ν¬λ„ŒνŠΈλ₯Ό μŠ€μΊ”ν•©λ‹ˆλ‹€.

 

 

 

ClassPathBeanDefinitionScanner

클래슀 κ²½λ‘œμ—μ„œ Bean 후보λ₯Ό νƒμ§€ν•˜λŠ” bean definition μŠ€μΊλ„ˆλ‘œ, (BeanFactory ν˜Ήμ€ ApplicationContext)의 λ ˆμ§€μŠ€νŠΈλ¦¬μ— λΉˆμ„ λ“±λ‘ν•©λ‹ˆλ‹€.

 

ν˜„μž¬ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ μ„€μ •ν•œ @Component μ–΄λ…Έν…Œμ΄μ…˜μ˜ λŒ€μƒμ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. (@Configuration, @RestController, @Service)

 

 

ClassPathBeanDefinitionScanner.doScan()

doScan() λ©”μ„œλ“œμ—μ„œ 핡심 κΈ°λŠ₯은 크게 μ»΄ν¬λ„ŒνŠΈ 후보 쑰회 -> beanName 생성 -> BeanDefinition 등둝 μž…λ‹ˆλ‹€.

  • findCandidateComponents() -> generateBeanName() -> registerBeanDefinition()

 

findCandidateComponents() λ©”μ„œλ“œλ‘œ 쑰회된 κ°μ²΄λ“€μž…λ‹ˆλ‹€.

직접 @Component λŒ€μƒμœΌλ‘œ λ“±λ‘λœ 3개의 객체듀이 μ‘΄μž¬ν•©λ‹ˆλ‹€.

 

ν•΄λ‹Ή μ»΄ν¬λ„ŒνŠΈλŠ” μ§€λ‚œ 번 Spring Bean 이 λ“±λ‘λ˜λŠ” κ³Όμ • μ—μ„œ μ‚΄νŽ΄λ΄€λ“―μ΄, DefaultListableBeanFactory ν΄λž˜μŠ€μ—μ„œ beanDefinitionMap 에 μ €μž₯ν•˜μ—¬ λΉˆμ„ 등둝&κ΄€λ¦¬ν•©λ‹ˆλ‹€.

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

 

 

λ°˜μ‘ν˜•

'Spring > Spring Internal' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

Spring Bean 이 λ“±λ‘λ˜λŠ” κ³Όμ •  (0) 2023.12.02

λŒ“κΈ€