당니의 개발자 스토리
Spring Bean과 Spring Container, 객체를 Spring이 관리하는 이유 본문
Spring에서 DI를 배우고 나면 자연스럽게 이런 생각이 든다.
"객체를 외부에서 넣어준다는 건 알겠어.
근데 대체 누가 객체를 만들고 관리하는 거지?"
여기서 등장하는 개념이 Spring Bean과 Spring Container다.
Spring에서는 객체를 개발자가 계속 직접 new로 만드는 방식보다,
Spring이 객체를 생성하고 관리하도록 맡기는 방식을 많이 사용한다.
그리고 Spring이 관리하는 객체를 Bean이라고 부른다.
이 구조를 이해하면 왜 Spring에서 @Component, @Service, @Repository, @Autowired 같은 어노테이션을 사용하는지도 자연스럽게 연결된다.
Spring Container란?
Spring Container는 Spring이 객체를 생성하고 관리하는 공간이다.
원래 자바에서는 객체를 직접 생성한다.
MemberService memberService = new MemberService();
이렇게 new를 사용해서 직접 객체를 만든다.
그런데 Spring에서는 객체를 개발자가 직접 계속 만들지 않는다.
대신 Spring Container가 객체를 만들고 보관한다.
그리고 필요한 곳에 객체를 넣어준다.
예를 들어 이런 코드가 있다고 해보자.
@Service
public class MemberService {
}
@Service를 붙이면 Spring은 실행될 때 이 클래스를 보고 객체를 생성한다.
그리고 Spring Container 안에서 관리한다.
즉, 개발자가 직접 new MemberService()를 호출하지 않아도 Spring이 객체를 만들어두는 것이다.
Bean이란?
Bean은 Spring이 관리하는 객체를 말한다.
@Service
public class MemberService {
}
즉, 이 객체는 Spring이 관리하므로 Bean이다.
반대로 그냥 일반 객체를 만들면 Bean이 아니다.
MemberService memberService = new MemberService();
그러므로, 얘는 Bean이 아니기 때문에 Spring Container가 관리하지 않는다.
즉 정리하면 이런 느낌이다.
그럼 왜 굳이 Spring이 객체를 관리할까?
가장 큰 이유는 객체 연결을 자동으로 해주기 때문이다.
예를 들어 회원 정보를 저장하는 Repository와 회원가입 로직을 처리하는 Service가 있다고 해보자.
@Repository
public class MemberRepository {
}
@Service
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
MemberService는 MemberRepository가 필요하다.
원래라면 개발자가 직접 객체를 만들고 연결해야 한다.
MemberRepository repository = new MemberRepository();
MemberService service = new MemberService(repository);
이렇게 직접 연결하는 것도 가능하다.
하지만 프로젝트가 커지면 객체 수가 엄청 많아진다.
Controller, Service, Repository, Config 객체들이 계속 늘어난다.
그걸 전부 개발자가 new로 만들고 연결하면 코드가 복잡해진다.
그래서 Spring이 대신 객체를 만들고 연결해주는 것이다.
Spring이 실행되면서
1. MemberRepository 객체 생성
2. MemberService 객체 생성
3. MemberService 생성자에 MemberRepository 넣기
이 과정을 자동으로 수행한다.
이걸 DI라고 했다.
즉, DI를 실제로 수행하는 주체가 Spring Container다.
@Component, @Service, @Repository는 왜 쓰는 걸까?
이 어노테이션들은 Spring에게 '이 객체를 관리해줘' 라고 알려주는 역할이다.
@Component
public class OrderService {
}
Spring은 이 클래스를 보고 Bean으로 등록한다.
@Service도 비슷하다.
@Service
public class MemberService {
}
기능적으로는 @Component와 거의 같다.
다만 역할을 더 명확하게 표현하기 위해 사용하는 것이다.
- @Controller → 요청 처리
- @Service → 비즈니스 로직
- @Repository → DB 접근
- @Component → 일반 컴포넌트
보통 이런 식으로 역할을 나눠서 사용한다.
@Autowired는 뭘까?
@Autowired는 필요한 객체를 자동으로 연결해달라는 의미다.
@Service
public class MemberService {
@Autowired
private MemberRepository memberRepository;
}
Spring은 MemberRepository Bean을 찾아서 자동으로 넣어준다.
다만 최근에는 필드 주입보다 생성자 주입을 더 많이 사용한다.
@Service
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
Spring은 생성자를 보고 필요한 객체를 자동으로 넣어준다.
왜 생성자 주입을 더 많이 사용할까?
이유는 안정성과 테스트 때문이다.
생성자 주입을 사용하면,
객체가 생성될 때 필요한 의존성이 반드시 들어오게 만들 수 있다.
예를 들어 MemberRepository 없이는 MemberService가 동작할 수 없다면,
생성자에서 무조건 받게 만드는 것이 더 안전하다.
그리고 테스트할 때도 편하다.
MemberRepository fakeRepository = new FakeMemberRepository();
MemberService service = new MemberService(fakeRepository);
이렇게 생성자 파라미터에 가짜 객체를 넣어서 테스트할 수 있다.
만약 클래스 내부에서 직접 new MemberRepository()를 했다면,
테스트용 객체로 바꾸기가 어려워진다.
싱글톤이란?
Spring Bean은 기본적으로 싱글톤으로 관리된다.
싱글톤은 객체를 하나만 생성해서 여러 곳에서 공유하는 방식이다.
예를 들어 MemberService Bean이 있다면,
요청이 올 때마다 계속 새 객체를 만드는 것이 아니라 하나를 만들어서 계속 재사용한다.
왜 이렇게 할까?
계속 새로 만들면 메모리 사용량이 늘어나고 성능도 떨어질 수 있기 때문이다.
특히 웹 서버에서는 동시에 수많은 요청이 들어온다.
그때마다 객체를 계속 새로 만들면 부담이 커질 수 있다.
그래서 Spring은 기본적으로 Bean을 하나만 생성하고 공유한다.
Bean 생명주기
Spring Bean도 생성되고 사라지는 과정이 있다.
1. 객체 생성
2. 의존성 주입
3. 초기화 작업
4. 사용
5. 종료 작업
예를 들어 DB 연결 객체라면 종료 전에 연결을 닫아야 할 수도 있다.
Spring은 이런 생명주기도 관리해줄 수 있다.
즉 Spring Container는 단순히 객체만 저장하는 것이 아니라,
객체 생성부터 관리, 연결, 종료까지 담당하는 공간이다.
'Java, Spring' 카테고리의 다른 글
| Maven, 빌드 자동화 도구에 대해서 (0) | 2026.05.06 |
|---|---|
| JUnit과 Assertion으로 테스트 코드 작성하기 (0) | 2026.05.06 |
| Spring의 DI, AOP, PSA, POJO 이해하기 (1) | 2026.05.06 |
| Spring이 JDBC와 트랜잭션 작업을 줄여주는 방식 (1) | 2026.05.06 |
| 프레임워크와 라이브러리의 차이, IoC 제어의 역전 (0) | 2026.05.04 |