Engineering
4. 스프링 빈과 의존관계
4. 스프링 빈과 의존관계 학습 내용을 정리한 백필 노트입니다.
이 글은 2025년 학습 기록을 블로그 형식으로 정리한 백필 노트입니다.
스프링에서 객체 간의 의존관계(Dependency) 를 효율적으로 관리하기 위한 핵심 개념은 스프링 빈(Spring Bean) 과 DI(Dependency Injection, 의존성 주입) 이다.
이 문서에서는 컴포넌트 스캔, 의존성 주입 방식, 스프링 빈 등록 방법 등을 다룬다.
1️⃣ 컴포넌트 스캔과 자동 의존관계 설정
💡 목적
회원 컨트롤러가 회원 서비스와 회원 리포지토리를 사용할 수 있도록 의존관계를 설정한다.
🧩 회원 컨트롤러 예시 코드
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
-
@Autowired가 생성자에 붙으면,스프링이 스프링 컨테이너에서 해당 타입의 객체를 찾아서 자동으로 주입(DI) 한다.
-
즉, 개발자가 직접 객체를 주입하지 않아도 스프링이 자동으로 처리한다.
⚠️ 발생 가능한 오류
Consider defining a bean of type 'hello.hellospring.service.MemberService' in your configuration.
이 오류는 MemberService가 스프링 빈으로 등록되어 있지 않아서 발생한다.
💬 참고: @Controller가 붙은 클래스(HelloController)는 스프링이 자동으로 스프링 빈으로 등록한다.
2️⃣ 스프링 빈 등록 방법
스프링 빈을 등록하는 방법은 두 가지다.
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록
3️⃣ 컴포넌트 스캔 원리
@Component애노테이션이 붙은 클래스는 자동으로 스프링 빈으로 등록된다.- 다음 애노테이션들은
@Component를 포함하고 있으므로 자동 등록 대상이다.@Controller@Service@Repository
4️⃣ 회원 서비스 스프링 빈 등록
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
@Service로 등록하면 스프링이 자동으로 스프링 빈으로 인식한다.@Autowired를 통해 스프링 컨테이너가MemberRepository객체를 주입한다.- 생성자가 하나뿐이면
@Autowired는 생략 가능하다.
5️⃣ 회원 리포지토리 스프링 빈 등록
@Repository
public class MemoryMemberRepository implements MemberRepository {}
@Repository가 붙으면 해당 클래스가 스프링 빈으로 등록된다.- 이렇게 등록된 빈은 컨테이너 내부에서 자동으로 관리된다.
6️⃣ 스프링 빈 등록 구조
-
memberService와memberRepository는 스프링 컨테이너에 스프링 빈으로 등록된다. -
스프링은 기본적으로 싱글톤(Singleton) 으로 빈을 등록한다.
즉, 동일한 빈 이름으로 등록된 객체는 하나의 인스턴스만 공유한다.
-
특별한 이유가 없는 한 대부분의 경우 싱글톤을 사용한다.
7️⃣ 자바 코드로 직접 스프링 빈 등록하기
다음과 같이 @Configuration + @Bean 조합으로 직접 등록할 수도 있다.
package hello.hellospring;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
-
향후 메모리 리포지토리를 다른 저장소로 교체할 예정이므로,
컴포넌트 스캔 대신 자바 코드 설정 방식을 사용한다.
-
XML 설정 방식도 가능하지만 최근에는 거의 사용하지 않는다.
8️⃣ DI(Dependency Injection) 방법 비교
DI에는 세 가지 방법이 있다.
| 구분 | 특징 | 권장 여부 |
| --- | --- | --- |
| 필드 주입 | @Autowired를 필드에 직접 지정 | ❌ 비권장 |
| Setter 주입 | Setter 메서드를 통해 주입 | ⚠️ 제한적 사용 |
| 생성자 주입 | 생성자를 통해 주입 | ✅ 권장 |
- 대부분의 경우 의존관계가 실행 중에 바뀔 일이 없으므로 생성자 주입을 권장한다.
9️⃣ 실무 적용 팁
-
정형화된 코드 (Controller, Service, Repository)
→ 컴포넌트 스캔 방식 사용
-
비정형 코드 / 상황에 따라 구현 변경 가능성 있음
→ 자바 코드로 직접 등록
🔒 주의사항
@Autowired를 통한 DI는 스프링이 관리하는 객체(스프링 빈) 에서만 동작한다.- 스프링 빈으로 등록되지 않은 직접 생성한 객체에서는 DI가 작동하지 않는다.
📚 참고
스프링 컨테이너와 DI의 동작 원리에 대한 심층 내용은
「스프링 핵심 원리」 강의에서 다룬다.
원문 요약: 스프링에서는 객체 간의 의존성을 관리하기 위해 빈(Bean)을 사용하며, 이를 자동 또는 수동으로 등록할 수 있다.
자동 등록은 @Component 기반 애노테이션으로 처리되고, 수동 등록은 @Configuration과 @Bean으로 명시적으로 정의한다.
DI는 생성자 주입이 가장 안정적이며, 대부분의 실무 코드에서 이 방식을 따른다.