본문 바로가기
Kotlin Spring/Kotlin Spring 강의 내용

3) Spring 컨테이너, Bean

by Bill Lab 2025. 8. 26.
728x90

1. "Spring 컨테이너"란?

“Spring 컨테이너는 커피숍의 바리스타와 같다”

     

      1) 커피숍에선 손님이 주문하면, 바리스타가 재료를 조합해서 커피를 만들어 줌

      2) 바리스타는 커피를 만들기 위해서 커피 원두, 우유, 시럽 등 필요한 재료들을 잘 보관, 관리함

      3) 바리스타가 모든 걸 직접 만들고, 관리하니 손님은 그냥 주문만 하면 됨

      4) 즉, Spring 컨테이너는 객체(Bean)를 생성하고, 관리하며, 필요할 때 꺼내주는 "바리스타" 같은 존재

2. Bean 이란?

Bean은 커피숍에서 만드는 ‘커피’ 한 잔'

 

      1) Bean은 "Spring 컨테이너"가 관리하는 "객체"

      2) 직접 new 해서 만드는 게 아니라, Spring이 대신 만들어서 관리해 줌

      3) 필요한 곳에서 바로 가져다 쓸 수 있도록 미리 만들어 두거나, 요청 시 만들어줌

          (싱글톤, 프로토타입 등 범위가 있음)

//Bean 등록하기(Component)

import org.springframework.stereotype.Component

@Component
class CoffeeMaker {
    fun brew(): String = "coffee"
}


//Service에 Bean 주입받기 
import org.springframework.stereotype.Service
import com.example.coffee.CoffeeMaker

@Service
class CoffeeShop(private val coffeeMaker: CoffeeMaker) {
    fun serveCoffee() = coffeeMaker.brew()
}

 

3. 왜 객체를 Spring 컨테이너가 관리할까?

       1) 객체 생성 책임을 개발자가 직접 지면 생기는 문제

            - 객체를 직접 new로 생성

            - 그 객체가 필요로 하는 의존 객체도 직접 생성

            - 생성 코드가 서비스 로직 안에 계속 들어옴

            - 코드가 점점 복잡해짐

            - 특정 구현체에 강하게 의존하게 됨

            - 하나를 바꾸면 여러 군데를 수정해야 함

"결국, 객체 관리 책임과 비즈니스 로직이 섞이게 되고, 코드의 역할이 분리되지 않는다"

 

       2) Spring 컨테이너가 대신 관리하면?

            - 객체 생성은 컨테이너가 담당

            - 의존성 자동 주입 (DI)

            - 라이프사이클 관리 (초기화 / 소멸)

            - 기본 싱글톤 관리

            - 필요 시 스코프 변경 가능

"개발자는 오직 비즈니스 로직에만 집중하면 된다"

 

      3) 핵심 개념: IoC (Inversion of Control)

            - Spring 이전의 전통적인 방식은 개발자가 객체를 직접 생성하고 제어 

            - Spring 방식은  컨테이너가 객체를 생성하고 주입 

"객체 생성과 관리의 주도권이 개발자에서 컨테이너로 넘어간 것 = 제어의 역전(IoC)"

 

 

4. DI를 사용하면 설계가 어떻게 좋아질까?

       1) 느슨한 결합 (Loose Coupling)

           - 직접 new로 객체를 만들면, 코드가 구현체 클래스에 강하게 의존하게 됨(구현 변경 시 코드 수정 발생)

CoffeeService service = new CoffeeService(new ArabicaBean());

         

           - DI를 사용하면 구현체가 바뀌어도 주입받는 쪽 코드는 변경 없이 그대로 사용 가능       

@Service
public class CoffeeService {
    private final Bean bean;
}
즉, “느슨한 결합(loose coupling)” 덕분에 유지보수, 확장성이 좋아짐
커피숍에서 원두를 바꾸고 싶을 때, "코드를 직접 수정하지 않고 Bean 설정만 바꾸면 끝!"

       

       2) 테스트 용이성 (Mocking 가능)

           - 직접 new를 사용하게되면 실제 객체 강제 사용
           - DI를 통해 Mock 객체를 주입 받게 되면, 실제 객체를 사용하지 않고 가짜객체 사용가능

단위 테스트가 쉬워지며, 테스트 코드와 운영 코드 분리 가능

 

 

       3) 스코프 및 라이프사이클 관리

           - Spring 기본제공기능은 Singleton, Prototype, Request, Session인데, 개발자가 직접 new로는 이런 관리가 어려움

           - (예시1)Singleton을 직접 관리할 경우

CoffeeService service = new CoffeeService();

              : 직접 생성한 객체를 여러 군데에서 호출하면? 객체가 계속 새로 만들어 지고, 싱글톤이 아님

                싱글톤으로 만들고 싶다면?

                 (1) static 변수로 직접 관리

                 (2) private 생성자
                 (3)getInstance() 패턴 구현

                즉, 우리가 직접 싱글톤 패턴을 구현해야 함 이로인해 코드 복잡도 증가, 관리 책임 증가 됨

"Spring은 이걸 자동으로 처리"

 

           - (예시2) Prototype 의 경우, 어디서 new를 호출할지, 누가 생성 책임을 가질지, 객체 소멸은 누가 관리할지

              전부 개발자가 설계해야 함.

"Spring은 @Scope("prototype")로 해결 가능"

 

5. 결론

직접 new하는 건 ?

: 요리사가 모든 재료를 직접 사서 바로바로 요리하는 것.

 

Spring Bean + DI는?
: 주방 매니저가 재료 준비하고, 레시피에 맞게 재료를 셰프에게 미리 갖다 주는 것.

요리사는 요리하는 데만 집중하고, 매니저는 재료 준비·관리 담당.

따라서 전체 주방 운영이 더 효율적이고 체계적임.

val result = "직접 new로 객체를 만들면 개발자가 모든 걸 관리해야 해서
변경, 테스트, 확장이 어렵고 코드가 복잡해집니다.

Spring 컨테이너가 Bean을 관리하면, 객체 생성과 의존성을 컨테이너가 책임져서 
개발자는 비즈니스 로직에만 집중할 수 있습니다.

이게 바로 IoC(제어의 역전)와 DI(의존성 주입)의 핵심 가치입니다."
728x90