본문 바로가기
Spring

스프링 빈과 의존 관계

by 토니짱 2022. 9. 25.

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

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

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

 

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

@Controller
public class MemberController {

  private final MemberService memberService;

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

@Controller 애너테이션을 붙이면 스프링 컨테이너가 MemberController를 생성해서 컨테이너에 넣어두고 관리한다.

생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이렇게 외부에서 객체 의존 관계를 넣어주는 것을 의존성 주입이라고 한다.

하지만 위처럼 하면 MemberService를 스프링 빈으로 등록하지 않았기 때문에 오류가 발생한다.

 

컴포넌트 스캔

@Component가 있으면 스프링 빈으로 자동 등록된다.

@Controller가 달린 컨트롤러가 자동으로 스프링 빈으로 등록된 이유도 @Controller안에 @Component가 포함되어 있기 때문에 컴포넌트 스캔이 되기 때문이다. @Service, @Repository 도 마찬가지

 

스플이 실행시 컴포넌트 관련 애너테이션이 있으면 모두 스캔해서 스프링 컨테이너에 등록한다.

@Autowired는 그걸 연결시켜주는 역할이다.

SpringBootApplication이 붙은 곳부터 하위 패키지만 스캔하기 때문에 다른 패키지의 클래스는 스캔하지 않는다.

 

 

회원 Service 스프링 빈 등록

@Service
public class MemberService {

  private final MemberRepository memberRepository;

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

생성자에 @Autowired를 붙이면 객체를 생성하는 시점에 해당 스프링 빈을 찾아 주입한다.

생성자가 1개라면 생략 가능

 

회원 Repository 스프링 빈 등록

@Repository
public class MemoryMemberRepository implements MemberRepository {

}

이제 MemberService와 MemberRepository가 스프링 컨테이너에 빈으로 등록되었다.

스프링은 스프링 컨테이너에 스프링 빈을 싱글톤으로 등록한다. 그래서 같은 스프링 빈이면 같은 인스턴스이다.

 

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

@Configuration
public class SpringConfig {

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

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

@Bean을 이용하여 스프링 빈으로 등록한다.

스프링이 실행되면 @Configuration을 읽고 @Bean이 붙어있으면 빈으로 등록한다.

그 후에 빈으로 등록된 MemberRepository를 MemberService에 주입한다.

만일 MemoryMemberRepository말고 다른 Repository로 변경한다면, 컴포넌트 스캔 대신 자바 코드로 빈을 설정하면 쉽게 바꿀 수 있다.

@Configuration
public class SpringConfig {

  ...

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

NewMemberRepository로 변경해주었다.

하지만 정형화된 컨트롤러, 서비스, 레파지토리는 컴포넌트 스캔을 사용한다.

 

DI 종류

필드 주입

@Controller
public class MemberController {

  @Autowired
  private final MemberService memberService;
}

스프링 실행시 처음 주입한 뒤로는 바꿀 수 있는 방법이 없다.

Setter 주입

@Controller
public class MemberController {

  private MemberService memberService;

  @Autowired
  public void setMemberService(MemberSerivce memberService) {
    this.memberService = memberService;
  }
}

생성은 생성대로 되고 setter는 나중에 호출되면서 memberService를 주입한다.

컨트롤러가 호출할 때 setter가 public으로 노출되어야 하기 때문에 누군가가 잘못 바꾸면 문제가 될 수 있다.

생성자 주입

@Controller
public class MemberController {

  private final MemberService memberService;

  @Autowired
  public void setMemberService(MemberSerivce memberService) {
    this.memberService = memberService;
  }
}

생성하는 시점에만 넣어두고 변경을 막을 수 있다. 의존 관계가 런타임 때 다른 것으로 바꿔치기되는 즉, 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.

 

Autowired 주의 사항

@Autowired를 통한 DI는 스프링이 관리하는 객체에서만 동작한다. 즉, 스프링 빈으로 등록하지 않고 직접 생성한 객체에서는 동작하지 않는다.

만약 자바 코드로 직접 등록하는 예시 소스에서 SpringConfig의 빈으로 등록된 코드를 지우면 @Autowired는 동작하지 않는다.

정리

  • @Component을 포함하고 있는 애너테이션은 자동으로 스프링 빈으로 등록되어 컴포넌트 스캔이 된다. 예)@Controller, @Service, @Repository
  • @Autowired는 스프링 빈으로 등록된 것들을 연결시켜주고 객체를 생성하는 시점에 스프링빈을 찾아 주입한다.
  • 컴포넌트 스캔은 @SpringBootApplication이 붙은 곳부터 하위 패키지만 이루어진다.
  • 스프링 컨테이너에 스프링 빈은 싱글톤으로 등록된다.
  • 자바 코드로 스프링 빈을 등록할 때에는 @Bean을 사용한다.
    @Configuration을 읽고 @Bean이 붙어있는 것들을 빈으로 등록해준다.

 

반응형

'Spring' 카테고리의 다른 글

AOP(Aspect Oriented Programming)  (3) 2022.09.25
@Component와 @Configuration  (1) 2022.09.25
스프링 웹 개발 기초  (1) 2022.09.25
사용중인 포트 죽이기  (2) 2022.09.24
Spring과 Spring Boot  (0) 2022.09.02