Taeyoung Kim

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️⃣ 스프링 빈 등록 방법

스프링 빈을 등록하는 방법은 두 가지다.

  1. 컴포넌트 스캔과 자동 의존관계 설정
  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️⃣ 스프링 빈 등록 구조

  • memberServicememberRepository는 스프링 컨테이너에 스프링 빈으로 등록된다.

  • 스프링은 기본적으로 싱글톤(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는 생성자 주입이 가장 안정적이며, 대부분의 실무 코드에서 이 방식을 따른다.