스터디/Spring

Spring 스터디 - 4

라퐁 2025. 2. 16. 17:52

컴포넌트 스캔과 자동 의존관계 설정

@Controller
public class MemberController {

    private final MemberService memberService;

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

MemberController 파일을 작성하고 잘 동작하는지 실행해보면 Parameter 0 of constructor in hello.hello_spring.controller.MemberController required a bean of type 'hello.hello_spring.service.MemberService' that could not be found.라는 오류가 발생한다. @Controller 어노테이션을 달고 있는 MemberController는 스프링 컨테이너가 시작 될 때 객체를 생성하지만, MemberService는 생성하지 않아서 발생하는 오류이다. 스프링 빈에 등록한다고 하는데, 스프링 빈에 등록하는 방법은 2가지가 있다.

  • 컴포넌트 스캔과 자동 의존관계 설정
  • 자바 코드로 직접 스프링 빈 등록하기
@Service
public class MemberService {
...
}

MemberService 앞에 @Service 어노테이션을 달면 스프링 빈에 등록된다. MemoryMemberRepository도 마찬가지고 @Repository 어노테이션을 등록하면 된다. 원래는 @Component 어노테이션이 스캔 대상이지만, @Controller, @Service, @Repository 어노테이션 안에도 @Component 어노테이션을 포함하고 있어서 스캔 대상(스프링 빈에 등록)에 포함된다.

@Service
public class MemberService {

    private final MemberRepository memberRepository;

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

MemberService 생성자에 @Autowired 어노테이션을 달면 객체 생성 시점에 스프링 컨테이너가 스프링 빈에서 내용을 찾아 의존성을 주입한다. 참고로 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다. 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다. 설정을 통해 싱글톤이 아니게 할 수 있으나, 특별한 경우를 제외 대부분 싱글톤을 사용한다.
 
싱글톤 패턴
 
클래스의 인스턴스를 하나만 생성하고, 이를 전역으로 공유하여 사용하는 디자인 패턴

  • 특징 : 인스턴스의 유일성 보장, 전역 접근 가능, 메모리 효율성(장점과 유사)
  • 단점 : 높은 결합도, 멀티스레드 문제, 테스트 어려움

스프링 빈
 
스프링 컨테이너에 의해 관리되는 Java 객체를 의미한다. 일반적인 Java 객체와 동일하지만, 스프링 컨테이너가 객체의 생성, 초기화, 의존성 주입, 소멸 등 생명 주기를 관리한다는 점에서 차이가 있다.

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

MemberService와 MemoryMemberRepository에 등록한 @Service, @Repository, @Autowired 어노테이션 제거 후 SpringConfig 클래스 작성한다.

@Configuration
public class SpringConfig {

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

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

@Configuration 어노테이션으로 시작하고, 각 스프링 빈에 추가할 객체에 대해서 @Bean 어노테이션을 달고 작성해준다. 이전에 어떤 형태로 데이터를 저장할지 정해진게 없어 Repository는 인터페이스 형태로 추가하였고, 현재는 MemoryMemberRepository를 사용하고 있다. 나중에 DB나 다른 형태로 변경 될 때 SpringConfig에서 내용만 바꿔주면 된다.