Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

국개장

[2025 스프링부트 스터디] #4주차 본문

카테고리 없음

[2025 스프링부트 스터디] #4주차

cho비상 2025. 5. 10. 02:58


섹션 5. 스프링 빈과 의존관계

 

 스프링을 쓰면 웬만한 것들은 다 스프링빈으로 등록해서 써야 한다. 그렇게 해야 얻는 이점이 많다고 한다.

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

 

 

 

  private final MemberService memberService = new MemberService();

위처럼 쓰면 각 컨트롤러에서 MemberService 객체를 별도로 다 만들게 되는 비효율이 발생한다.

 

그러므로 spring container에 등록을 하고 사용해서 객체 하나만 만들어지도록 하자.

 

 

  private final MemberService memberService;

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

이렇게 memberService 생성자 오버로딩을 작성하고, @Autowired를 추가해준다. 이렇게 하면 멤버 서비스를 스프링 컨테이너에 있는 멤버 서비스에 연결을 딱 해준다고 한다. (중복 데이터 방지?)

 

하지만 이것만으로는 충분치 않다. 서비스 코드를 보면 이는 그저 순수한 자바 코드이기 때문에, 스프링에서 인식하려면 서비스 클래스에 추가로 @Service라는 구문을 작성해주어야 한다고 한다. 이렇게 해주면 그제서야 얘를 서비스라고 인식하고 스프링 컨테이너에 멤버 서비스를 딱 등록해준다.

...

import org.springframework.stereotype.Service;

...

@Service
public class MemberService {
  // private final MemberRepository memberRepository = new MemoryMemberRepository();

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

 

레포지토리도 마찬가지로 스프링이 인식하도록 @Repository 구문을 추가한다.

 

...

import org.springframework.stereotype.Repository;

...

@Repository
public interface MemberRepository {
  Member save(Member member);

...

 

그리고, repository 또한 @Autowired를 하여 스프링 빈에 등록한다.

 

import org.springframework.beans.factory.annotation.Autowired;

...

@Service
public class MemberService {
  // private final MemberRepository memberRepository = new MemoryMemberRepository();

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

...

 

 

memerService와 memberRepository가 스프링 컨테이너에 스프링 빈으로 등록되었다.

 

스프링 빈을 등록하는 2 가지 방법

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

2. 자바 코드로 직접 스프링 빈 만들기

 

우리는 방금 위에서 스프링 빈을 등록하는 방법 중 첫 번째 방법을 적용한 것이다. 

 

 

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

- '@Component' 애노테이션이 있으면 스프링 빈으로 자동 등록된다.

- '@Controller' 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.

 

- '@Component'를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다. 

    - '@Controller'

    - '@Service'

    - '@Repository'

 

 

 

 

 

아무대나 @Component를 붙여서 패키지를 만든다고 다 스프링 빈이 되는 것은 아니다. 우리는 이 폴더 구조에서 SpringBootStudyApplication.java를 실행시키고 있기 때문에 저 파일과 연결된 패키지 내의 하위 패키지들 까지만 처리를 하여 스프링 디너로 등록해준다.

 

 

스프링 빈은 기본적으로 싱글 톤이라고 한다. 인스턴스를 하나만 만든다는 것이다. 설정에 따라 여러 개 존재하게 할 수 있지만, 대부분 싱글 톤이 쓰인다고 한다.

 

 


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

 

위 경로에 SpringConfig 클래스 파일을 만든다.

 

package wink.spring_boot_study;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import wink.spring_boot_study.repository.MemberRepository;
import wink.spring_boot_study.repository.MemoryMemberRepository;
import wink.spring_boot_study.service.MemberService;

@Configuration
public class SpringConfig {


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

위와 같이 '@Bean' 애노테이션을 쓰면, 스프링 빈을 직접 만들어서 지정해줄 수 있다. 위의 컴포넌트 스캔 방식과 동일한 구조가 됐다.

 

 

 

참고 : XML로 설정하는 방식도 있지만 최근에는 잘 사용하지 않으므로 생략한다.

 

생략.

 

 

 

참고: DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.

@Controller
public class MemberController {

  @Autowired private MemberService memberService;

}

필드 주입 방식, 이렇게 하면 스프링 들 때만 얘를 넣어주고 이거를 중간에 내가 바꿔치기 할 수 있는 방법이 아예 없다.

 

@Controller
public class MemberController {
  private MemberService memberService;

  @Autowired
  public void setMemberService(MemberService memberService) {
    this.memberService = memberService;
    // memberService.setMemberRepository(); // 호출되지 말아야할 메서드가 호출되면 안된다.
  }
}

setter 주입 방식, 누군가가 멤버 컨트롤을 호출했을 때 이게 public으로 열려 있어야 하는데, 그러면 누군가가 set함수 호출해서 바꾸면 문제가 생기게 된다.

 

 

 

 

참고 : 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.

@Configuration
public class SpringConfig {


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

구현체 변경 시 직접 빈 구현 방식으로는 저렇게 memory를 실제 DB로 바꿔주기만 하면 된다고 한다. 컴포넌트 방식일 경우에는 하나하나 수정해주어야 하는 번거로움이 있다.

 

 

 

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

 

컴포넌트나 @Bean을 해주지 않고 @Autowired만 해준 상태에서는 의존성 주입이 동작하지 않는다는 의미이다.

 

 

 

 

더 이상의 자세한 설명은 생략한다. (스프링 핵심 원리 강의 홍보)

 

 

 

 

 

Comments