스프링

스프링 빈의 스코프와 생명주기

yoon4360 2025. 4. 1. 22:14

 

스프링을 사용하다 보면 종종 궁금해진다.

“이 빈은 왜 한 번만 생성되지?”
“매번 새로운 인스턴스를 받고 싶은데 어떻게 하지?”
“공유되는 빈을 여러 스레드에서 써도 괜찮을까?”

 

이런 궁금증은 모두 스프링 빈의 스코프(scope)생명주기 개념과 관련 있다.
이번 글에서는 싱글톤, 프로토타입, @Scope, @Lazy 등 빈의 생성 방식과 사용 시 주의할 점을
정리해보겠다.

 


 

스프링 빈 스코프란?

빈은 스프링 컨테이너가 생성하고 관리하는 객체다.

빈 스코프는 스프링이 빈 인스턴스를 언제, 얼마나 자주 생성할지를 결정하는 설정이다.

대표적인 두가지 스코프는 다음과 같다.

  • singleton: 하나의 인스턴스를 앱 전역에서 공유 (기본값)
  • prototype: 요청할 때마다 새로운 인스턴스 생성

 


 

싱글톤 스코프  @Scope("singleton")

 

특징

 

  • 스프링의 기본 스코프이다. (별도 설정 없이 자동 적용)
  • 컨텍스트에 등록된 후 하나의 인스턴스를 앱 전역에서 공유한다.
  • @Component, @Service, @Repository, @Bean 등 모두 사용 가능하다.

 

장점
  • 메모리 효율이 좋다.
  • 의존성 주입이 간단하다.

 

주의점
  • 여러 컴포넌트에서 동시에 접근시 동시성 이슈가 발생할 수 있다.
  • 만약 싱글톤 빈이 상태를 가지면 경쟁 조건이 발생할 수 있다.
@Component
public class SharedCounter {
    private int count = 0;

    public void increase() {
        count++; // 여러 스레드에서 동시 접근 시 위험
    }
}

 

 

그렇다면 동기화하면 해결될까?

가능은 하지만 성능저하가 심각해진다. 

락이 걸려 동시에 한 스레드만 접근 가능해지고, CPU의 자원이 낭비 된다. 그리고 데드락의 위험도 있다.

 

따라서 가능하면 싱글톤 빈은 상태를 갖지 않게 설계하는 것이 좋다.

 


 

프로토타입 스코프 @Scope("prototype")

 

특징
  • 스프링은 요청이 있을 때마다 새 인스턴스를 생성한다.
  • 스프링 컨테이너는 객체 생성만 하고, 이후 생명주기는 직접 관리하지 않는다.
  • 동시성 이슈가 없다. → 각 스레드는 자신만의 인스턴스를 사용한다.

 

사용 시점
  • 요청마다 다른 데이터나 상태를 저장해야 할 때
  • 가변 데이터를 다뤄야 할 때

 

주의점
  • 싱글톤 빈에 주입할 때 주의해야한다.
@Component
public class MyService {

    // 이건 한 번만 주입되고 계속 같은 인스턴스 사용됨
    private final TempObject tempObject;

    public MyService(TempObject tempObject) {
        this.tempObject = tempObject;
    }
}

TempObject가 프로토타입 스코프라도, 싱글톤에서는 한번 주입되면 같은 인스턴스만 사용되기에 처음 한번만 생성된다.

 

이 경우 ObjectProvider, ApplicationContext.getBean() 을 사용하면 된다.

 


 

지연로딩 @Lazy

@Component
@Lazy
public class HeavyService {
    public HeavyService() {
        System.out.println("무거운 서비스 생성됨");
    }
}
  • @Lazy를 붙이면 빈을 실제로 사용할 때까지 생성하지 않는다.
  • 앱 시작 시점에 모든 빈을 미리 만들 필요가 없을 때 유용하다.
  • 메모리 낭비 방지, 시작 속도 향상 가능하다.

 

사용 시점
  • 모놀로식 앱에서 모든 기능을 초기에 쓰지 않을 경우
  • 무거운 로직을 가진 컴포넌트

 


 

싱글톤 vs 프로토타입

스코프 singleton prototype
기본값
인스턴스 수 하나 요청할 때마다 새로 생성
상태 관리 불변 상태 권장 가변 상태 사용 가능
동시성 문제 주의 필요 없음
메모리 사용 효율적 많아질 수 있음
주입 시 주의 없음 싱글톤에 주입 시 한 번만 생성됨

 

즉시 vs 지연 인스턴스 생성

구분 즉시 생성 지연생성(@Lazy)
생성 시점 앱 시작 시 바로 생성 사용할 때 생성
메모리 사용 전체 빈을 모두 로딩 필요한 빈만 로딩
성능 초기 로딩 시간이 길 수 있음 필요할 때만 비용 발생
에러 감지 앱 실행 시 바로 발견 사용 시점까지 지연됨

 


 

마무리

 

  • 스프링 빈은 무조건 싱글톤이면 좋은 게 아니다.
  • 빈이 상태를 가지면 동시성 문제를 반드시 고려해야 한다.
  • 가변 상태가 필요한 경우엔 @Scope("prototype")으로 관리하면 된다.
  • 앱 초기 속도나 메모리 최적화가 필요하다면 @Lazy로 지연 생성을 활용하자.