본문 바로가기
BackEnd/Spring

[스프링 입문] 회원 관리 예제 - 스프링 빈과 의존관계

by 개발 Blog 2024. 7. 1.

공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.

인프런 스프링 입문 (김영한)

 

스프링 빈을 등록하는 방법에는 2가지가 있다.

1. 컴포넌트 스캔

2. 자바 코드로 직접 빈 등록

 

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

이전 시간에 만든 회원 서비스를 완성도 있게 만들려면 Controller와 view가 필요하다. (회원가입 결과를 HTML로 뿌려주기 위해)

-> 이 과정을 멤버 컨트롤러가 멤버 서비스를 의존한다 라고 표현한다.

 

1. MemberController를 생성한다.

package hello.hello_spring.controller;

import hello.hello_spring.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;
    }
}
  • 스프링 컨테이너가 처음 생성될 때 @Controller 애노테이션이 있으면, Spring에 Controller 객체를 생성해서 넣고 관리한다.
    • 이것을 스프링 컨테이너에서 스프링 빈이 관리된다고 표현한다.
  • MemberService를 new를 이용하여 객체를 생성할 수도 있다. 하지만 이렇게 되면 다른 여러 컨트롤러들이 멤버 서비스를 가져다가 사용하는 문제가 생긴다. 따라서 스프링 컨테이너에 등록하고 사용하는 것이 좋다.
    • 생성자에 @AutoWired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 

2. 여기까지 과정을 그림으로 보면 아래와 같이 표현할 수 있다.

인프런 스프링 입문(김영한)

3. 아직 memberService는 스프링 빈으로 등록되어 있지 않다.

4. MemberService도 스프링 빈에 등록해주기 위해 @Service 애노테이션을 붙여준다.

5. MemoryMemberRepository도 애노테이션을 붙여준다.

6. 이제 스프링 빈에 controller, service, repository가 등록/연결이 되었다.

인프런 스프링 입문(김영한)

7. 이러한 방식이 컴포넌트 스캔 방식이다.

-> controller, service, repository 각각의 애노테이션에는 @Componet가 선언되어 있다. 

* 컴포넌트 스캔 : 스프링 컨테이너에 등록

* Autowierd : 연관관계

 

8. 컴포넌트 스캔 원리

  • @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.
  • @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
  • @Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
    • @Controller
    • @Service
    • @Repository

9. 아무 파일에나 @Componet가 있다고 스프링 빈으로 컴포넌트 스캔이 되는 것은 아니다.

  • SpringApplication의 패키지를 포함한 하위 패키지만 스캔한다. 
  • 즉, package hello.hello_spring 안에 있는 파일들만 스캔한다.

참고 : 스프링은 기본적으로 스프링 빈을 싱글톤으로 등록하여, 동일한 빈은 모두 같은 인스턴스를 공유한다. 특별한 경우가 아니면 대부분 싱글톤을 사용한다.

 

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

1. service와 repository의 애노테이션을 제거한다. (@Service, @Repository)

2. SpringConfig 클래스를 생성한다.

package hello.hello_spring;

import hello.hello_spring.repository.MemberRepository;
import hello.hello_spring.repository.MemoryMemberRepository;
import hello.hello_spring.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();
    }
}
  • @Configuration : 스프링 컨테이너는 @Configuration이 붙어있는 클래스를 자동으로 빈으로 등록하게 된다.
  • @Bean : 수동으로 스프링 빈을 등록한다.
  • memberService()와 memberRepository()를 스프링 빈에 등록하고, 스프링 빈에 등록되어 있는 memberRepository()를 memberService()의 인자로 넣어준다.

그러면 아래와 같은 그림처럼 등록된다.

인프런 스프링 입문(김영한)

3. DI(의존성 주입)에는 필드주입, setter 주입, 생성자 주입 3가지 방법이 있다.

 

필드주입

- 필드주입은 추천하지 않는다. spring이 처음 실행할 때만 넣어주고, 중간에 바꿀 방법이 없다.

 

setter주입

- 누군가가 멤버를 호출했을 때 public으로 열려있어야 하는 단점이 있다.

- 한번 메서드를 작성하고 나면 중간에 바꿀 일이 없는데, 항상 public으로 노출이 된다. (수정될 가능성 있음)

 

생성자 주입

- 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.

 

* 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고

정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.

 

* 주의 : @Autowired 를 통한 DIhelloController, memberService 등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.