[Spring] @Component와 @ComponentScan 사용해 자동으로 의존성 주입하기
@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는 다음 페이지에서 확인할 수 있습니다.