seonggoc

4. 스프링 빈과 의존관계 (김영한 스프링 입문 강의 정리) 본문

Spring

4. 스프링 빈과 의존관계 (김영한 스프링 입문 강의 정리)

seonggoc 2025. 2. 12. 14:59

기술적인 부분은 영어 표현이 더 많이 쓰이므로 스프링과 연관된 기술 부분은 영어로 표기를 진행한다.

앞서 만든 Spring 예제에서 Controller가 Service를 통해 회원가입과 조회 기능을 쓸 수 있어야한다.

실행하면 Controller가 MemberService를 통해 가져와야하는데 Spring Contatiner에는 MemberService가 없어 등록을 해줘야한다.
Spring Bean은 등록하는 과정이라고 볼 수 있다.

기능을 사용하기 위해서는 2가지 방법이 있다.

  1. Component Scan과 Automatic Dependency Injection
  2. Java 코드로 직접 Spring Bean 등록

Component Scan과 Automatic Dependency Injection

Spring Bean : Spring이 직접 관리하는 Instance를 Spring Bean이라고 한다.

@Component, @Service, @Repository, @Controller와 같은 Annotation을 붙이게 되면 Spring Bean에 등록된다.

사용하는 이유

// controller/MemberController.java

@Controller
public class MemberController {
    private final MemberService memberService = new MemberService();
}

코드를 짤 때 이런식으로 코드를 짜게되면 문제점이 있다.
new로 생성하여 사용하면 Spring Bean에 등록되지않아 MemberService를 변경하게 되면 그때 그때 MemberController 코드도 수정해야한다.

  • 추가적으로 GPT한테 물어봤다.

Component Scan 사용 방법

이제부터 본격적으로 Component Scan을 활용한 Automatic Dependency Injection를 해보자.

@Controller
public class MemberController {
    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

위 코드처럼 생성자에 @Autowired가 있으면 Spring과 연관된 Instance를 Spring Container에서 찾아 넣어준다.
이렇게 외부에서 넣어주는걸 DI(Dependency Injection)라고 한다.

조금 더 찾아보니 DI 방식은 3가지가 있다.

  1. 생성자 주입 방식
  2. 필드 주입 방식
  3. 세터 주입 방식

거의 대부분은 생성자 주입 방식을 사용한다고 한다. 다른 방식은 살짝 알아만 보고 어쩌다 사용하게 될 때 그때가서 공부해도 늦지 않을 것 같다.

위에서 처럼 넣으면 될 것 같지만 오류가 발생한다. 생성자의 매개변수인 MemberService는 그냥 Java Class이기 때문에 Spring이 알 수 없다.

MemberService 위에도 Annotation을 붙여줘야한다.
Service 부분에는 @Service, Repository부분에는 @Repository를 붙여준다.

그리고 위처럼 Service에도 @Autowired를 붙여줘야한다.

@Service
public class MemberService {
    // 저장소
    private MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
@Repository
public class MemoryMemberRepository implements MemberRepository {
    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;

지금까지 넣은 방식은 Component Scan를 활용한 DI 방식이다.

Spring은 Spring Container에 Bean을 등록할 때, 기본적으로 싱글톤 패턴을 사용한다. 특수한 상황에 사용할 수도 있으나 지금은 싱글톤만 학습

Java 코드를 통한 Spring Bean 등록

지금까지 넣은 @Service, @Repository, @Autowired를 지워서 DI를 없애고 시작해야한다.
Controller부분은 그대로 두고, Service와 Repository만 지운다.

public class MemberService {

    private final MemberRepository memberRepository;

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

Service는 지운다. Repository도 마찬가지로 지워주면 된다.
그리고 실행을 해보면 오류가 발생한다.

Java 코드를 통한 등록 방법

hello.hellospring에 SpringConfig file을 만든다.

@Configuration
public class SpringConfig {

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

위처럼 코드를 삽입하면 Bean에 등록이 된다.
일반적으론 Component Scan 방식을 선호하고 구현 클래스가 여러개 있어서 자주 바꿔야한다면 Java 코드를 통한 방법도 좋다.