Post

Spring Bean

Spring에서 객체를 Bean으로 관리하는 이유

Spring Bean

Spring에서 객체를 Bean으로 관리하는 이유

bean에서 대해서 설명하기 전, java의 이름 유래부터 알고 가면 흥미로울 것이다.
왜 빈이라고 작명했냐면 일단 자바라고 이름 지은 것도 자주 마시는 커피가 인도네시아 자바 섬 커피였기 때문이라고 한다. (그래서 자바의 브랜드 이미지가 커피잔이 있는 것이다!)
이 때문에 재사용이 가능한 자바 객체를 커피콩에 비유해서 Bean이라고 정정했다.
자바언어에서 스프링 프레임워크로 확장되면서 스프링 bean이라는 명칭까지 이어진게 된 것이다.

1. 의존성 관리 자동화

빈으로 등록된 객체들은 Spring 컨테이너(BeanFactory, ApplicationContext)가 자동으로 의존성을 주입해준다.
개발자가 직접 객체를 생성하고 의존성을 연결할 필요가 없어진다.
또 컨테이너가 빌드 시점에 순환 의존성을 감지하여 설계 오류를 조기에 발견할 수 있다.

1
2
3
4
5
@Service
class OrderService(
    private val productRepository: ProductRepository,  // 자동 주입
    private val paymentGateway: PaymentGateway        // 자동 주입
)

2. 싱글톤 패턴 구현

기본적으로 Spring은 빈을 싱글톤으로 관리하여 메모리 사용을 최적화하고, 불필요한 객체 생성을 방지한다.

1
2
3
4
5
6
// 아래 두 userRepository는 동일한 인스턴스
@Service
class UserService(private val userRepository: UserRepository)

@Service
class AuthService(private val userRepository: UserRepository)

3. 생명주기 관리

Spring은 빈의 초기화와 소멸 과정을 자동으로 관리합니다. 이를 통해 리소스 할당 및 해제를 체계적으로 처리할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
@Component
class DatabaseConnection {
    @PostConstruct
    fun initialize() {
        // 초기화 로직
    }
    
    @PreDestroy
    fun cleanup() {
        // 리소스 정리 로직
    }
}

4. AOP(관점 지향 프로그래밍) 지원

빈으로 관리되는 객체들은 트랜잭션 관리, 로깅, 보안 등의 공통 관심사를 쉽게 적용할 수 있다.

1
2
3
4
5
6
7
@Service
class TransferService(private val accountRepository: AccountRepository) {
    @Transactional  // AOP를 통한 트랜잭션 관리
    fun transferMoney(from: String, to: String, amount: BigDecimal) {
        // 송금 로직
    }
}

5. 테스트 용이성

빈으로 관리되는 컴포넌트는 모킹(mocking)이나 테스트용 구현체로 쉽게 대체할 수 있어 단위 테스트와 통합 테스트가 용이하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@SpringBootTest
class UserServiceTest {
    @MockBean
    lateinit var userRepository: UserRepository
    
    @Autowired
    lateinit var userService: UserService
    
    @Test
    fun testGetUser() {
        // given
        val userId = 1L
        whenever(userRepository.findById(userId)).thenReturn(User(userId, "Test User"))
        
        // when
        val result = userService.getUser(userId)
        
        // then
        assertEquals("Test User", result.name)
    }
}

6. 설정의 중앙화

애플리케이션의 구성 요소들을 Bean으로 관리함으로써 설정을 중앙화하고 일관된 방식으로 관리할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
class AppConfig {
    @Bean
    fun dataSource(): DataSource {
        return HikariDataSource().apply {
            jdbcUrl = "jdbc:postgresql://localhost:5432/mydb"
            username = "user"
            password = "password"
            maximumPoolSize = 10
        }
    }
}
This post is licensed under CC BY 4.0 by the author.