Spring/Dependency Injection

[Spring] @Component와 @ComponentScan 사용해 자동으로 의존성 주입하기

Dev.Cho 2024. 11. 16. 07:41

@Bean 어노테이션 사용해 Bean 등록하기

이전 글에서 유저 정보를 조작하는 UserRepository 인터페이스를 구현하는 객체가 InMemoryUserRepository와 DbUserRepository 두개가 있고, 이 중 하나를 UserCreator 클래스에서 사용한다고 했을 때 코드를 다음과 같이 구성했었다.

interface UserRepository {
    fun createUser(id: String, user: String)
}

class InMemoryUserRepository(): UserRepository {
    override fun createUser(id: String, user: String) {
        println("User $user created with id: $id in InMemoryUserRepository")
    }
}

class DbUserRepository(): UserRepository {
    override fun createUser(id: String, user: String) {
        println("User $user created with id: $id in DbUserRepository")
    }
}
class UserCreator(private val repository: UserRepository) {
    fun createUserWithRandomId(user: String) {
        val id = UUID.randomUUID().toString()
        repository.createUser(id, user)
        println("[User Creation Success] User $user id: $id")
    }
}

 

그리고 Configuration 파일 내부에 @Bean 어노테이션을 사용해 Bean을 다음과 같이 구성했다.

@Configuration
class UserContainerConfiguration {
    @Primary
    @Bean
    fun inMemoryUserRepository(): UserRepository {
        return InMemoryUserRepository()
    }

    @Qualifier("dbUserRepository")
    @Bean
    fun dbUserRepository(): UserRepository {
        return DbUserRepository()
    }

    @Bean
    fun userCreator(@Qualifier("dbUserRepository") repository: UserRepository): UserCreator {
        return UserCreator(repository)
    }
}

 

하지만, 매번 이렇게 Configuration 파일 내부에 @Bean 어노테이션을 통해 Bean을 등록하는 것은 번거롭다.

Spring은 Bean을 더 편하게 등록하기 위한 방법을 제공하는데, 그 방법이 바로 @Component 어노테이션을 통해 Bean을 등록하는 방법이다. 지금부터 그 방법에 대해 알아보자.

 

@Component 어노테이션 사용해 Bean 등록하기

@Component를 통해 Bean을 등록하는 방법은 매우 간단하다. 단순히 각 클래스 위에 @Component를 붙이면 된다. 또한 만약 둘 이상의 구현체가 있을 때 붙이는 @Primary 어노테이션과 @Qualifier 어노테이션은 @Component 와 함께 붙이면 된다.

 

앞서 @Bean 어노테이션이 붙은 inMemoryUserRepository에 @Primary가 붙어있었고, dbUserRepository 위에 @Qualifier("dbUserRepository")가 붙어 있었으니 똑같이 @Component 위에 각 어노테이션을 붙이면 된다. 예를 들어 UserRepository 인터페이스를 구현하는 InMemoryUserRepository와 DbUserRepository는 다음과 같이 설정하면 된다.

package com.kotlinworld.spring.di.section6

..

interface UserRepository {
    fun createUser(id: String, user: String)
}

@Primary
@Component
class InMemoryUserRepository(): UserRepository {
    override fun createUser(id: String, user: String) {
        println("User $user created with id: $id in InMemoryUserRepository")
    }
}

@Qualifier("dbUserRepository")
@Component
class DbUserRepository(): UserRepository {
    override fun createUser(id: String, user: String) {
        println("User $user created with id: $id in DbUserRepository")
    }
}

 

마찬가지로 UserCreator 위에도 @Component를 붙이고, 생성자의 UserRepository 인자 앞에 @Qualifier("dbUserRepository")를 붙이면 DbUserRepository 객체가 주입된다.

package com.kotlinworld.spring.di.section6

..

@Component
class UserCreator(
    @Qualifier("dbUserRepository") private val repository: UserRepository
) {
    fun createUserWithRandomId(user: String) {
        val id = UUID.randomUUID().toString()
        repository.createUser(id, user)
        println("[User Creation Success] User $user id: $id")
    }
}

 

이후 UserContainerConfiguration을 모두 비우고 위에 @ComponentScan을 붙여 놓으면, UserContainerConfiguration 클래스가 있는 패키지와 하위의 모든 @Component Annotation이 붙은 클래스들이 스캔돼 Bean으로 등록된다.

package com.kotlinworld.spring.di.section6

..

@ComponentScan
@Configuration
class UserContainerConfiguration {

}

 

이제 각 Bean이 모두 제대로 등록됐는지 확인하기 위해 다음 코드를 실행해보자.

fun main(args: Array<String>) {
    val context = AnnotationConfigApplicationContext(UserContainerConfiguration::class.java)

    context.beanDefinitionNames.forEach { 
        println(it)
    }
}

 

그러면 다음과 같이 모든 Bean 들이 잘 등록된 것을 볼 수 있다.

 

마지막으로 UserCreator에 DbUserRepository가 제대로 등록됐는지도 확인해보자. 이를 위해 UserCreator Bean을 가져온다음 createUserWithRandomId 함수를 호출한다.

fun main(args: Array<String>) {
    val context = AnnotationConfigApplicationContext(UserContainerConfiguration::class.java)
    
    context.getBean(UserCreator::class.java).createUserWithRandomId("세영")
}

 

그러면 다음과 같은 로그가 나오는 것을 볼 수 있다. 유저 생성을 위해 DbUserRepository가 사용된 것을 볼 수 있다. 

 

여기까지 @Component와 @ComponentScan을 사용해 Bean을 등록하는 방법을 살펴봤다.

 

하지만 매번 @Bean 대신 @Component를 사용할 수 있는 것은 아니다. 이어서 어느 경우에 @Bean을 사용해야 하고 @Component를 사용해야 하는지 알아보자.

 

전체 코드: GitHub
이 프로젝트가 도움이 되셨다면 저장소에 Star⭐️를 눌러주세요! Stargazers는 다음 페이지에서 확인할 수 있습니다.
반응형