Programming/Spring

Spring Bean / IoC Container / DI

osean 2023. 1. 21. 09:55

  • Spring Bean
  • Spring IoC Container
  • Dependency Injection (DI)
    • Constructor Injection
    • Method Injection
    • Setter Injectio

Spring Bean 으둜 λ“±λ‘λœ ν΄λž˜μŠ€λŠ” IoC Contrainer 에 μ˜ν•΄ μƒμ„±λœ Singleton 객체λ₯Ό μ˜λ―Έν•˜λ©°, Bean 으둜 λ“±λ‘λœ 클래슀만 μ»¨ν…Œμ΄λ„ˆλ₯Ό 톡해 μ˜μ‘΄μ„±μ΄ μ£Όμž…(Dependency Injection)λ˜μ–΄ 객체의 생λͺ…μ£ΌκΈ°λ₯Ό κ°œλ°œμžκ°€ μ•„λ‹Œ μ»¨ν…Œμ΄λ„ˆκ°€ κ΄€λ¦¬ν•˜λ„λ‘ ν•œλ‹€.

Register Bean

  • @Bean
    • @Bean 은 @Configuration 이 뢙은 DI μ„€μ •μš© ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©λ˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ, λ©”μ†Œλ“œλ₯Ό μ΄μš©ν•΄ Bean Object 의 생성과 의쑴 관계 μ£Όμž…μ„ μˆ˜ν–‰ν•œλ‹€.
@Configuration
class DataSourceConfig {
    @Bean
	fun dataSource(): DataSource {
        val dataSource = SimpleDriverDataSource()

        dataSource.setDriverClass(Driver::class.java)
        dataSource.url = "jdbc:mysql://localhost/springbook?characterEncoding=UTF-8"
        dataSource.username = "user"
        dataSource.password = "password"

        return dataSource
    }
}
  • @Autowired
    • Spring Framework λŠ” @Autowired κ°€ 뢙은 μˆ˜μ •μž λ©”μ†Œλ“œ(Setter) κ°€ 있으면 νŒŒλΌλ―Έν„° νƒ€μž…μ„ 보고 μ£Όμž… κ°€λŠ₯ν•œ νƒ€μž…μ˜ Bean 을 λͺ¨λ‘ κ²€μƒ‰ν•˜μ—¬ μ£Όμž…ν•œλ‹€.
    • 이같은 @Autowired μ–΄λ…Έν…Œμ΄μ…˜μ„ μ΄μš©ν•˜λ©΄ μ†μ‰½κ²Œ μ˜μ‘΄μ„±μ„ μ£Όμž…ν•  수 μžˆμ–΄ DI κ΄€λ ¨ μ½”λ“œλ₯Ό λŒ€ν­ 쀄일 수 μžˆμ–΄μ„œ μ½”λ“œλ₯Ό κ°„κ²°νžˆ μž‘μ„±ν•  수 μžˆλŠ” μž₯점이 μžˆμ§€λ§Œ, Bean μ„€μ • 정보λ₯Ό 보고 λ‹€λ₯Έ 빈과의 의쑴 관계가 어떀지 νŒŒμ•…ν•˜κΈ° νž˜λ“€λ‹€λŠ” 단점이 μžˆλ‹€.
    • 단, 의쑴 객체의 κ΅¬ν˜„μ²΄κ°€ 두 개 이상인 경우 κ΅¬ν˜„μ²΄ λ³„λ‘œ λ‹€λ₯Έ Bean 이름을 μ„€μ •ν•˜μ—¬ μ΅œμ’… 후보λ₯Ό μ„ νƒν•˜λ„λ‘ λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.
      • @Component("AComponentImpl") 와 같이 Bean 객체의 이름을 μ§€μ •ν•œλ‹€.
// ProductServiceConfig
@Configuration
class ProductServiceConfig(
  	@Autowired
	private val productRepository: ProductRepository
) {
	@Bean
	fun productService(): ProductService = ProductService(productRepository)
}

// ProductRepositoryConfig
@Configuration
class ProductRepositoryConfig() {
	@Bean
	fun productRepository(): ProductRepository = ProductRepository()
}
  • @Component
    • ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ€ ν΄λž˜μŠ€μ—μ„œ μ‚¬μš© κ°€λŠ₯ν•˜λ©° Bean Scanner λ₯Ό 톡해 μžλ™μœΌλ‘œ Bean 객체둜 λ“±λ‘λœλ‹€.
    • @Componenet μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•΄ Bean 으둜 λ“±λ‘ν•˜λ €λ©΄ @ComponentScan κ³Ό 같은 μ–΄λ…Έν…Œμ΄μ…˜μ„ μΆ”κ°€μ μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ μ–΄λ–€ λ²”μœ„κΉŒμ§€ μŠ€μΊ”ν•  것인지 μ„€μ •ν•˜λŠ” 과정이 ν•„μš”ν•˜λ‹€.
      • @ComponentScan @Component 및 ν•˜μœ„ μ–΄λ…Έν…Œμ΄μ…˜μ΄ 뢙은 클래슀λ₯Ό μ–΄λŠ λ²”μœ„κΉŒμ§€ 검색할 수 μžˆμ„μ§€ μ„€μ •ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€. νŒ¨ν‚€μ§€λ₯Ό κΈ°μ€€μœΌλ‘œ ν•˜λ©° μ„€μ • κ°€λŠ₯ν•œ νŒ¨ν‚€μ§€λŠ” 닀쀑 선택이 κ°€λŠ₯ν•˜λ‹€. 
    • @Controller, @Service, @Repository λ“±
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component
annotation class WebAdapter(
    @get:AliasFor(annotation = Component::class)
    val value: String = ""
)

Spring IoC Container() λŠ” DI(Dependency Injection) κ³Ό λ°€μ ‘ν•œ 관계λ₯Ό λ§Ίκ³  μžˆλ‹€. μ΄λŸ¬ν•œ Spring Container λŠ” λ‹€μŒκ³Ό 같은 κ²½μš°μ— 객체λ₯Ό μ •μ˜ν•˜λ„λ‘ ν•˜λŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό κ±°μΉœλ‹€.

ApplicationContext λŠ” Spring IoC Container 의 Bean 클래슀의 μΈμŠ€ν„΄μŠ€ν™”, ꡬ성 및 쑰립 등을 λ‹΄λ‹Ήν•˜λŠ” 역할이닀. 이둜 인해 μ»¨ν…Œμ΄λ„ˆλŠ” μ„€μ • 메타데이터 λ₯Ό 톡해 Bean μΈμŠ€ν„΄μŠ€ 생성 섀정을 읽어 듀인닀. μ„€μ • λ©”νƒ€λ°μ΄ν„°λŠ” XML μ΄λ‚˜ Java Annotation, Java Code λ“±μœΌλ‘œ μ„€μ • κ°€λŠ₯ν•˜λ‹€.

Spring Framework λŠ” ApplicationContext μΈν„°νŽ˜μ΄μŠ€μ˜ μ—¬λŸ¬ κ΅¬ν˜„μ²΄λ₯Ό μ œκ³΅ν•˜λŠ”λ°, ClassPathxmlApplicationContext, FileSystemXmlApplicationContext 클래슀의 μΈμŠ€ν„΄μŠ€κ°€ μ‚¬μš©λ˜λŠ” 것이 μΌλ°˜μ μ΄λ‹€. κΈ°μ‘΄μ—λŠ” XML 을 톡해 μ„€μ • 메타데이터λ₯Ό μ •μ˜ ν–ˆμœΌλ‚˜ μ΄λŸ¬ν•œ ν˜•μ‹μ„ Java Annotation μ΄λ‚˜ Code λ₯Ό μ΄μš©ν•΄ μ„ μ–Έμ μœΌλ‘œ μž‘μ„±ν•  수 μžˆλ„λ‘ μ»¨ν…Œμ΄λ„ˆμ—μ„œ μ‘°μž‘ κ°€λŠ₯ν•˜λ‹€.

Config Metadata Annotation

  • @Import
    • @Configuration으둜 μ„€μ •ν•œ νŒŒμΌμ„ 두 개 이상 μ‚¬μš©ν•˜λŠ” 경우
@Import(QueryFactoryConfig::class)
@Configuration
class JpaQueryFactoryConfig {

    @PersistenceContext
    private lateinit var entityManager: EntityManager

    @Bean
    fun queryFactory() = JPAQueryFactory(this.entityManager)
}
  •  @DependsOn
    • 빈이 λ“±λ‘λ˜λŠ” μˆœμ„œλ₯Ό μ§€μ •ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜
@Component("calculator-2")
@DependsOn(value = ["calculator-1"])
class Calculator(
        var number: Int
)

Dependency Injection(DI)λŠ” Bean κ°μ²΄μ—μ„œ ν•„μš”ν•œ μ™ΈλΆ€μ˜ Bean 객체λ₯Ό μ£Όμž…ν•˜λ„λ‘ ν•˜λŠ” ν”„λ‘œμ„ΈμŠ€μ΄λ‹€. μ΄λŸ¬ν•œ DI 원칙에 μ˜ν•΄ μ½”λ“œλ₯Ό κΉ”λ”ν•˜κ²Œ μž‘μ„±ν•  수 μžˆμ–΄λ©°, 객체 κ°„ 쒅속성에 λŒ€ν•œ Decoupling 을 효과적으둜 λ‹€λ£° 수 μžˆλ‹€. λ˜ν•œ, 의쑴이 ν•„μš”ν•œ Bean κ°μ²΄λŠ” μ™ΈλΆ€μ—μ„œ μ£Όμž…λ°›λŠ” Bean 객체의 μœ„μΉ˜λ‚˜ κ΅¬ν˜„μ²΄λ₯Ό μ•Œ 수 μ—†λ‹€. 즉, μΈν„°νŽ˜μ΄μŠ€λ‚˜ 좔상 클래슀λ₯Ό μ£Όμž… λ°›μŒμœΌλ‘œμ¨ ν…ŒμŠ€νŠΈ 진행이 μš©μ΄ν•΄μ§€λ„λ‘ ν•˜λ©° μœ μ—°ν•œ ν™•μž₯이 κ°€λŠ₯ν•˜λ„λ‘ ν•œλ‹€. μ΄λŸ¬ν•œ DI λŠ” κ°œλ°© 폐쇄 μ›μΉ™μ˜ κ΄€μ μ—μ„œ νμ‡„μ˜ κ΄€μ μ—μ„œ λ³Ό λ•Œ μž¬μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€λŠ” 점은 μ² μ €νžˆ ν•΄λ‹Ή 원칙을 μ€€μˆ˜ν•˜κ³  μžˆλ‹€κ³  λ³Ό 수 μžˆλ‹€.

DI ν™œμš© 방법

  • 핡심 κΈ°λŠ₯ λ³€κ²½
    • 의쑴 λŒ€μƒμ˜ κ΅¬ν˜„μ„ λ°”κΏ” 핡심 κΈ°λŠ₯의 λ™μž‘ 방식을 λ‹€λ₯Έ κ΅¬ν˜„μ²΄λ‘œ λ³€κ²½ ν•  수 μžˆλ‹€. μ΄λŸ¬ν•œ νŠΉμ§•μ€ κΈ°μ‘΄ JDBC λ₯Ό μ‚¬μš©ν•˜λ‹€κ°€ JPA λ‚˜ MyBatis λ“±μœΌλ‘œ κ΅¬ν˜„μ²΄λ₯Ό ν†΅μ§Έλ‘œ λ³€κ²½ν•˜λŠ” κ²ƒμœΌλ‘œ μ˜ˆμ‹œλ₯Ό λ“€ 수 μžˆλ‹€.
  • 핡심 κΈ°λŠ₯의 동적인 λ³€κ²½
    • DI λŠ” 기본적으둜 λŸ°νƒ€μž„ μ‹œ λ™μ μœΌλ‘œ 의쑴 였브젝트λ₯Ό μ—°κ²°ν•΄μ£Όμ§€λ§Œ, ν•œ 번 μ˜μ‘΄μ„±μ΄ μ£Όμž…λ˜κ³  λ‚˜λ©΄ κ·Έ ν›„λ‘œλŠ” κ΅¬ν˜„μ²΄κ°€ λ³€κ²½λ˜μ§€ μ•ŠλŠ”λ‹€. 즉, 정적인 κ΄€κ³„λ‘œ μ˜κ³€κ΄€κ³„λ₯Ό λ§Ίμ–΄μ£ΌλŠ” 것이닀. ν•˜μ§€λ§Œ DI λ₯Ό 잘 ν™œμš©ν•˜λ©΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ™μž‘ν•˜λŠ” 쀑간에 μ˜μ‘΄ν•˜λŠ” κ΅¬ν˜„μ²΄λ₯Ό λ™μ μœΌλ‘œ λ³€κ²½ν•  수 μžˆλ‹€. μ΄λŠ” Dynamic Routing Proxy / Proxy Object 기법을 ν™œμš©ν•˜μ—¬ μ‘μš©ν•  수 μžˆλ‹€.
    • νšŒμ›μ˜ 등급에 따라 λ‹€λ₯Έ κ΅¬ν˜„μ²΄λ₯Ό μ‚¬μš©ν•˜λ„λ‘ ν•˜κ±°λ‚˜ μ‚¬μš©μžλ³„λ‘œ 독립적인 의쑴 였브젝트λ₯Ό μ‚¬μš©ν•˜κ²Œλ” ν•œλ‹€.
  • λΆ€κ°€ κΈ°λŠ₯ μΆ”κ°€
    • κΈ°μ‘΄ κ΅¬ν˜„λœ 핡심 κΈ°λŠ₯은 κ·ΈλŒ€λ‘œ 둔채 μΆ”κ°€μ μœΌλ‘œ λΆ€κ°€ κΈ°λŠ₯을 κ΅¬ν˜„ ν•  수 μžˆλ‹€. κ·Έ μ˜ˆμ‹œλ‘œ Decorator νŒ¨ν„΄μ΄ μžˆλ‹€. 의쑴 μ˜€λΈŒμ νŠΈλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜κ²Œ ν•˜λ„λ‘ ν•˜κ³ , μ‹€μ œ μ‚¬μš©ν•  μ˜€λΈŒμ νŠΈλŠ” DI λ₯Ό μ μš©ν•˜λ„λ‘ ν•˜λ©΄ Decorator νŒ¨ν„΄μ„ μ‰½κ²Œ μ μš©ν•  수 μžˆλ‹€.
  • μΈν„°νŽ˜μ΄μŠ€ λ³€κ²½
    • Proxy
      • ν•„μš”ν•œ μ‹œμ μ—μ„œ μ‹€μ œ μ‚¬μš©ν•  였브젝트λ₯Ό μ΄ˆκΈ°ν™”ν•˜κ³  λ¦¬μ†ŒμŠ€λ₯Ό μ€€λΉ„ν•˜κ²Œ ν•΄μ£ΌλŠ” Lazy Loading 적용 μ‹œ Proxy 객체λ₯Ό μ΄μš©ν•˜λ„λ‘ ν•œλ‹€.
    • Template / Callback
      • 반볡적으둜 λ“±μž₯ν•˜μ§€λ§Œ 항상 고정적인 μž‘μ—… 흐름과 κ·Έ μ‚¬μ΄μ—μ„œ 자주 λ°”λ€ŒλŠ” 뢀뢄을 λΆ„λ¦¬ν•΄μ„œ Template κ³Ό Callbak 으둜 λ§Œλ“€μ–΄ DI 원리λ₯Ό μ‘μš”ν•΄ μ μš©ν•˜λ©΄ 반볡적으둜 μž‘μ„±λœ μ§€μ €λΆ„ν•œ μ½”λ“œλ₯Ό κ°„κ²°ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€.
    • Singleton / Object Scope
      • Spring DI λŠ” 기본적으둜 Singleton 으둜 Bean 객체λ₯Ό λ§Œλ“€μ–΄ μ‚¬μš©ν•˜λ„λ‘ ν•œλ‹€. 이 덕뢄에 IoC Container λŠ” Bean 으둜 λ“±λ‘λœ Singleton 객체의 생λͺ…μ£ΌκΈ°λ₯Ό 직접 μ œμ–΄ν•˜κ²Œ λ˜μ–΄ κ°œλ°œμžλŠ” 이λ₯Ό ν™œμš©ν•΄ 자유둭게 섀계할 수 μžˆλ‹€λŠ” μž₯점을 가진닀.
      • λ•Œλ‘œλŠ” Singleton 생λͺ…μ£ΌκΈ° 뿐만 μ•„λ‹ˆλΌ μž„μ˜μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό κ°–λŠ” 객체가 ν•„μš”ν•  λ•Œλ„ μžˆλ‹€. HTTP μš”μ²­ λ‹Ή ν•˜λ‚˜μ˜ 객체가 λ§Œλ“€μ–΄μ§€κ±°λ‚˜, HTTP Session ν•˜λ‚˜ λ‹Ή μƒˆλ‘œμš΄ 객체가 λ§Œλ“€μ–΄μ§€κ²Œλ” ν•  수 μžˆλ‹€.
    • Test
      • 의쑴 객체λ₯Ό λŒ€μ‹ ν•΄μ„œ λ™μž‘ν•  Stub / Mock 객체λ₯Ό μ΄μš©ν•΄ ν…ŒμŠ€νŠΈμ— μ‚¬μš©ν•  수 μžˆλ‹€. DI λ₯Ό μœ„ν•΄ λ§Œλ“  μˆ˜μ •μž λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ ν…ŒμŠ€νŠΈ μ½”λ“œ μ•ˆμ—μ„œ μˆ˜λ™μœΌλ‘œ Mock 객체λ₯Ό μ£Όμž…ν•  수 μžˆλ‹€.

μ˜μ‘΄μ„± μ£Όμž… 방식

  • Constructor Inject
    • μƒμ„±μž 기반 DI λŠ” μ»¨ν…Œμ΄λ„ˆκ°€ μƒμ„±μžλ₯Ό 톡해 μ—¬λŸ¬ 인자λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ˜μ‘΄μ„±μ„ μ£Όμž…ν•˜κ²Œ λœλ‹€. μ΄λŠ” 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” 것와 λ™λ“±ν•˜λ©°, 의쑴 인자λ₯Ό μœ μ‚¬ν•˜κ²Œ 닀룬닀.
@RestController
class ProductController(
	private val getProductsUseCase: GetProductsUseCase
)
  • Setter Inject
@RestController
class ProductController(
	lateinit var getProductsUseCase: GetProductUseCase
)
  • Field Inject
@RestController
class ProductController(
    @Autowired
    private val getProductUseCase: GetProductUseCase
)

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

[QueryDSL] NoSuchMethodError Trouble Shooting  (0) 2023.02.22
Criteria API  (0) 2023.01.28
JPA / Persistence Context / Transactional  (2) 2023.01.14
Spring | Spring Framework ?  (0) 2020.08.02
IntelliJ | Spring MVC + Maven ν”„λ‘œμ νŠΈ λ§Œλ“€κΈ° (Oracle)  (0) 2020.07.26