<Spring> 스프링 빈 등록하기와 의존관계 설정

해당 글은 김영한님의 <스프링 입문> 강좌를 기반으로 작성되었습니다.
  • 스프링 빈을 등록하는 방법 두가지에 대한 포스팅입니다.

Component Scan과 자동 의존관계 설정

회원 Controller에 의존관계 추가

package hello.hellospring.controller;

import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller // annotation 역할 :  spring bean으로 해당 클래스를 spring-container에서 관리
public class MemberController {

    private final MemberService memberService;

    @Autowired//Controller 와 Service 간의 연결 수행하는 어노테이션
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}


  • 생성자에 @AutoWired가 있으면 스프링이 연관된 객체(여기서는 MemberService)를 찾아서 알아서 연결해준다. 이런 식으로 외부에서 객체 의존관계를 주입해주는 것을 DI라고 한다. 이전 테스트 케이스 작성에서는 개발자가 직접 코딩으로 넣는 방식이었고, 여기서는 @AutoWired에 의해 스프링이 직접 의존관계를 주입해준다.
  • 만약 Controller만 스프링 빈으로 등록하면 아래와 같은 에러가 발생한다.
  • 이는 스프링 컨테이너가 MemberController는 찾았지만 MemberService는 찾지 못해서 발생했다.
  • 이를 해결하기 위해 우리는 Service,Repository 객체도 스프링 빈으로 등록해야 한다.

서비스와 레포지토리 객체 스프링 빈 등록하기

@Service//서비스 스프링 빈으로 등록
public class MemberService {
    private final MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository  = memberRepository;
    }
	...
}
@Repository//레포지토리 스프링 빈으로 등록
public class MemoryMemberRepository implements MemberRepository{}

Component Scan 원리

  • @Component 어노테이션이 붙어있으면 스프링 빈에 자동 등록된다.
  • @Service, @Repository, @Controller@Component를 가지고 있는 어노테이션들이다. 그래서 스프링 빈에 자동 등록된다.
  • @ SpringBootApplication 어노테이션은 @ComponentScan이라는 어노테이션을 포함하고 있다.
  • @ComponentScan 어노테이션은 해당 클래스와 같은 Level의 패키지의 하위 클래스들에 대해 컴포넌트 스캔을 진행하면서 객체를 스프링 빈에 등록한다.
  • 참고로, 스프링은 스프링 컨테이너에 스프링 빈을 등록할때 기본으로 싱글톤으로 등록한다.(유일하게 하나만 등록해서 그걸 공유하는 방식) 따라서 동일한 스프링 빈이라면 동일한 인스턴스이다.

자바 코드로 직접 스프링 빈 등록하기

  • 회원 서비스와 회원 레포지토리의 @Service, @Repository, @Autowired를 삭제하고 나서 진행합니다.
  • hello.hellospring 패키지 밑에 바로 SpringConfig 클래스를 아래와 같이 작성합니다.
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();
      }
}
  • SpringConfig가 직접 스프링 등록하기 위한 클래스임을 설정하는 @Configuration 어노테이션을 달아준다.
  • 이후, 각각의 MemberService, MemberRepository에 대해서 @Bean 어노테이션을 달아주고 리턴 값으로 자기자신의 생성자 또는 메모리 구현체를 넘긴다.

언제 자바 코드로 직접 스프링 빈 등록하는 방식이 컴포넌트 방식보다 유리할까?

  • 대부분의 정형화된 실무에서 사용하는 구조는 편리한 컴포넌트 방식으로 스프링 빈을 등록하지만, 정형화된 틀이 없거나 상황에 따라 구현 클래스를 직접 수정해야 하는 일이 있는경우에는 SpringConfig로 직접 스프링 빈을 등록하는게 유리하다.
  • 예를들어 해당 프로젝트 DB대신 메모리 레포지토리를 사용하고 있기에 추후에 변경할 예정이므로 컴포넌트 스캔 방식보다 SpringConfig 방식이 좀 더 유리하다.