[spring 입문] 스프링 빈과 의존관계

채원·2024년 2월 10일

스프링

목록 보기
6/18
post-thumbnail

출처) 인프런 스프링 입문 강의

스프링 빈 등록 방법

1) 컴포넌트 스캔 & 자동 의존 관계 설정

  • 컴포넌트 스캔
    @Controller, @Service, @Repository
    스프링이 컴포넌트와 관련된 어노테이션이 있으면 객체를 생성해서 스프링 컨테이너에 등록
  • 자동 의존관계 설정
    @AutoWired
    ⭐️ application 하위페이지는 컴포넌트 스캔으로 스프링 빈에 등록되지만, 하위 페이지가 아닌 경우 등록 X
    2) 자바 코드로 직접 스프링 빈 등록

스프링 빈 등록

controller가 service, repository 사용할 수 있게 의존관계를 추가해야함

1) 컴포넌트 스캔 & 자동 의존 관계 설정

MemberController 생성
이렇게 @Controller 어노테이션만 있어도 (안에 아직 코드를 작성하지 않았어도)
springboot가 스프링 컨테이너 안에 객체를 만들어줌

@Controller
public class MemberController {
    
}

MemberService 의 경우 인스턴스를 controller마다 여러개 생성할 필요없이 하나를 생성하고
controller끼리 공유하는 것이 좋다
➡️ spring container에 하나를 등록하고 Autowired로 주입하면 됨

@Controller
public class MemberController {
    private final MemberService memberService;

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

이 상태에서는 오류 발생!
MemberService는 순수한 class 즉, spring이 얘가 있는지 모른다 ...
== ⭐️ 스프링 빈으로 등록되어 있지 않다
따라서 Autowired를 해도 연결할 수 없음

1) MemberService를 스프링 빈으로 등록해야함 ➡️ @Service 어노테이션 추가하기

import org.springframework.stereotype.Service;
import java.util.Optional;

@Service
public class MemberService {

2) MemberRepository도 등록 -> @Repository 어노테이션 추가하기
MemberRepository는 구현체에다 적어주면 됨

@Repository
public class MemoryMemberRepository implements MemberRepository{

그림처럼 controller - service를 연결하기 위해 위에서 적었던 autowired가 잘 됨

controller가 생성 될 때 스프링 빈에 등록된 service를 가져다가 넣어줌
== 의존성 주입

그리고 service - repository를 를 연결하기 위해 service에도 autowired 해줌

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

⭐️ 정리

  • service는 하나의 인스턴스만 생성하여 컨트롤러끼리 공유한다
    스프링은 스프링 컨테이너에 빈을 등록할 때 싱글톤으로 등록 (하나만 등록하여 공유)함
    같은 스프링 빈 == 같은 인스턴스
  • controller - service - repository 의존 관계를 가진다
  • service와 repository도 각 @Service @Repository 어노테이션을 적어 스프링 빈에 등록 필요
  • 각 의존 관계 연결하고 의존성 주입을 하기 위해서 @Autowired 어노테이션 추가
  • controller는 service 생성시, service는 repository 생성시에 의존성 주입

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

MemberService에서 @service, @authowired 삭제
MemoryMemberRepository에서 @Repository삭제

컴포넌트 스캔이 아닌 직접 등록하는 방식

hello.hellospring > service > 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();
    }
}

controller는 컴포넌트 스캔 방식 그대로 사용

  • service, repository는 config 파일에서 직접 자바 코드로 등록함
  • Configuration, @Bean 사용
  • MemberService 생성시 Repository 생성 메서드를 호출해서 인자로 레포지토리를 주게끔
    일종의 autowired랑 비슷한 개념으로 사용

참고

  • 실무에서는 정형화된 컨트롤러, 서비스, 레포지토리는 같은 컴포넌트 스캔을 사용함
    ⭐️정형화되어 있지 않거나, 상황에 따라 구현 클래스 변경이 필요한 경우 설정을 통해 스프링빈으로 등록
    ex) MemoryMemberRepository에서 다른 구현 클래스로 변경하는 경우, 다른 MemberService 등을 건드리지 않고 해당 코드만 수정하면 됨
...
    @Bean
    public MemberRepository memberRepository(){
        return new DBrepository(); // 여기만 수정 (구현 클래스 변경)
    }
}
  • @AutoWired를 통한 의존성 주입은 스프링이 관리하는 객체(컨테이너에 올라가있는)에서만 동작함
    ex) SpringConfig 파일 내 Bean 코드를 주석처리하는 경우 MemberSerive에 AutoWired 동작하지 않음

추가) 의존성 주입 종류

DI (의존성 주입)에는 필드 주입, setter 주입, 생성자 주입 등 3가지 방법이 있음
의존 관계가 동적으로 변하는 경우는 없으므로 생성자 주입 권장

생성자 주입
생성하는 시점만 가능하고 이후 변경이 불가

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

필드 주입 (권장 X)

@Autowired private MemberService memberService;

세터 주입
public으로 노출되어서, 생성 이후에도 호출될 수 있음

priavte MembeerService memberService;
@AutoWired
public setMemberService(MemberService memberService){
	this.memberService = memberService; 
    }

0개의 댓글