[스프링] 스프링 컨테이너와 빈(Bean)은 왜 필요한가?

2025. 6. 26. 20:15·스프링

스프링(Spring)에서 가장 기본이 되는 개념 중 하나는 스프링 컨테이너와 빈이다. 스프링을 사용하면 객체를 직접 생성하지 않고, 스프링이 대신 생성하고 관리해준다. 그리고 그렇게 관리되는 객체를 '빈(Bean)'이라고 부른다.

 

그런데 왜 굳이 스프링이 객체를 대신 만들어주고 관리해야 할까? 단순히 new로 객체를 생성하면 되는 것 아닌가? 이 질문에 대한 답은 실제 코드를 통해 쉽게 이해할 수 있다.

 

예를 들어 어떤 서비스 클래스가 있다고 해보자. 그 클래스 안에서 직접 필요한 객체를 생성하는 전통적인 방식은 다음과 같다.

public class MemberService {

    private final MemoryMemberRepository repository;

    public MemberService() {
        this.repository = new MemoryMemberRepository();
    }

    public void join(String name) {
        repository.save(name);
    }
}

 

이 구조는 단순해 보이지만 이전 "스프링이란 무엇일까?" 파트에서 봤듯, 치명적인 문제를 안고 있다. MemberService가 구체적인 구현체인 MemoryMemberRepository에 강하게 의존하고 있기 때문이다. 나중에 저장 방식을 DB로 바꾸기 위해 DbMemberRepository를 만들었다고 가정하면, MemberService의 코드를 직접 수정해야 한다. 기능 하나 바꾸려는데 코드 여러 곳이 동시에 깨지는 현상이 발생한다. 이는 객체 지향 설계 원칙인 DIP(의존 역전 원칙)과 OCP(개방-폐쇄 원칙)를 위배하는 구조이다.

 

이 문제를 해결하는 가장 좋은 방법은 역할과 구현을 분리하는 것이다. 즉, 인터페이스를 만들고, 구현체는 나중에 주입받는 방식이다.

public interface MemberRepository {
    void save(String name);
}
@Repository
public class MemoryMemberRepository implements MemberRepository {
    public void save(String name) {
        System.out.println("메모리에 저장: " + name);
    }
}
@Service
public class MemberService {

    private final MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public void join(String name) {
        memberRepository.save(name);
    }
}

이 구조에서 MemberService는 구체 클래스가 아닌 인터페이스(MemberRepository)에만 의존한다. 어떤 구현체가 들어올지는 전혀 신경 쓰지 않는다. 실제 구현체(MemoryMemberRepository)는 스프링이 실행 시점에 자동으로 찾아서 주입해준다. 이 기능을 가능하게 해주는 것이 바로 스프링 컨테이너이며, 이때 주입되는 객체가 빈(Bean)이다.

 

스프링 컨테이너는 @Component, @Service, @Repository 등이 붙은 클래스를 자동으로 스캔하여 객체를 생성하고, 이를 내부 저장소에 빈으로 등록한다. 그리고 @Autowired가 붙은 생성자나 필드에 타입에 맞는 빈을 찾아 주입한다. 이렇게 객체를 스프링이 대신 관리하고 연결해줌으로써, 개발자는 역할 중심의 설계에만 집중할 수 있고, 구현은 자유롭게 바꾸거나 확장할 수 있게 된다.

 

결론적으로, 스프링 컨테이너는 객체를 대신 만들고 관리하고 연결까지 해주는 '중앙 관리자'이며, 빈은 그 컨테이너가 관리하는 객체이다. 이 구조 덕분에 우리는 객체 간의 결합도를 낮추고, 변화에 유연한 코드를 작성할 수 있다. 스프링을 사용하는 이유는 결국 이런 설계 철학을 자연스럽게 구현할 수 있기 때문이다.

'스프링' 카테고리의 다른 글

[스프링] 빈 스코프  (1) 2025.07.24
[스프링] 빈 생명주기 콜백  (3) 2025.07.24
[스프링] 의존관계 자동 주입에 대하여  (0) 2025.06.26
[스프링] 싱글톤과 스프링 컨테이너에 대하여  (3) 2025.06.26
[스프링] 스프링이란 무엇일까?  (0) 2025.06.26
'스프링' 카테고리의 다른 글
  • [스프링] 빈 생명주기 콜백
  • [스프링] 의존관계 자동 주입에 대하여
  • [스프링] 싱글톤과 스프링 컨테이너에 대하여
  • [스프링] 스프링이란 무엇일까?
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    QueryDSL
    백준
    스프링
    mvc
    spring
    SOLID
    객체지향
    BFS
    스프링 데이터 JPA
    코딩 테스트
    예외 처리
    쿼리dsl
    Java
    LocalDateTime
    스프링 컨테이너
    dfs
    thymeleaf
    예외처리
    자바
    컬렉션
    최적화
    쿼리
    SpringDataJpa
    코딩테스트
    불변객체
    재귀
    fetch join
    JPA
    타임리프
    다형성
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[스프링] 스프링 컨테이너와 빈(Bean)은 왜 필요한가?
상단으로

티스토리툴바