TaBo
개척하는 기록
TaBo
전체 방문자
오늘
어제
  • 기록들 (63)
    • Programming (35)
      • Java (19)
      • Servlet&Jsp (4)
      • Spring (4)
      • SpringBoot (1)
      • 기타 (2)
      • BOJ (5)
    • CS (16)
      • 자료구조 (4)
      • 알고리즘 (4)
      • 운영체제 (5)
      • 기본 용어 (3)
    • Project (4)
      • [Spring] 게시판 (4)
    • 나에 대한 기록 (8)

블로그 메뉴

  • Github

인기 글

태그

  • OS
  • 백준
  • 자바
  • 운영체제
  • java
  • c++
  • Spring 게시판
  • 알고리즘
  • 스프링 게시판
  • spring

최근 글

티스토리

hELLO · Designed By 정상우.
TaBo

개척하는 기록

[Spring] 여러가지 DI 방법, 의존관계 자동 주입(@Autowired)
Programming/Spring

[Spring] 여러가지 DI 방법, 의존관계 자동 주입(@Autowired)

2023. 4. 10. 13:02

※ 본문은 인프런 김영한님의 스프링 강의를 바탕으로 학습한 내용을 기록한 글입니다.

오개념이 있다면 댓글로 알려주세요!

 

[ 1 ] 여러가지 DI 방법

(1) 생성자 주입

- 생성자 호출 시점에 딱 1번만 호출되는 것이 보장되므로 불변, 필수 의존관계에 사용하는 것이 좋다.

- 생성자가 1개만 있다면 @Autowired 를 생략할 수 있다.

 

[ Config에서 DI ]

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

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

 

[ 의존 자동주입 ]

@Component
public class MemberService {

    private final MemberRepository memberRepository;

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

 

 

(2) setter

- 자바 빈 프로퍼티 규약의 setter를 사용하여 DI를 할 수 있다.

- 의존 자동주입을 하려면 setter에 @Autowired 애노테이션을 설정하면 된다.

- 선택, 변경 가능성이 있는 의존관계에 사용할 수 있다.

 

[ 의존 자동주입 ]

@Component
public class MemberService {

    private MemberRepository memberRepository;

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

 

 

(3) 필드 주입

- 코드가 간결해지지만, 외부에서 변경이 불가능하기 때문에 테스트하기 힘들다는 단점이 있다. 

- 테스트 환경에서 의존관계를 변경하려면 setter를 추가해야 한다.

- 즉, DI 프레임워크가 없으면 아무것도 할 수 없기 때문에 필드 주입을 지양하자.

 

[ 의존 자동주입 ]

@Component
public class MemberService {

    @Autowired
    private MemberRepository memberRepository;
    
}

 

 

(4) 일반 메서드 주입

- 생성자나 setter가 아닌 일반적인 메서드에도 @Autowired를 사용하여 의존 자동주입을 할 수 있다.

- 그러나 일반적으로 잘 사용하지 않는다.

 

 


[ 2 ]  생성자 주입을 선택해야 하는 이유 

일반적으로 애플리케이션 종료시점까지 의존관계를 변경할 일이 없다. 오히려 대부분의 의존관계는 애플리케이션이 종료되기 전까지 불변해야 한다.

 

setter는 접근제어자가 public이기 때문에 누군가 실수로 의존관계를 변경하는 문제가 발생할 수 있다. 반면, 생성자 주입은 객체 생성 시 딱 1번만 호출되는 것이 보장되므로 이후에 호출될 일이 없다. 따라서 생성자 주입을 사용하는 것이 좋은 설계 방법이다.

 

또한, 생성자 주입을 사용하면 필드에 final 를 사용할 수 있으므로 생성자에서 값이 설정되지 않는 오류를 컴파일 시점에 막아준다는 이점이 있다. 즉, 컴파일 오류를 통해 DI를 누락하는 문제를 방지할 수 있는 것이다.

 

 


[ 3 ] @Autowired 의존 자동주입 및 주의점

@Autowired 를 활용하여 의존 자동주입을 하기 위해서는 주입할 객체가 스프링 컨테이너에 등록된 스프링 빈이어야 한다(@Autowired의 required 옵션 기본 값이 true이기 때문). 만약 주입할 객체가 등록된 스프링 빈이 아니라면 UnsatisfiedDependencyException 이 발생한다.

 

하지만, 스프링 빈이 아니더라도 의존 자동 주입을 동작하게 하는 세 가지 방법이 있다. 

(1) @Autowired(required = false) : 주입할 객체가 등록된 스프링 빈이 아니라면 의존 주입 메서드 자체가 호출되지 않는다.

(2) @Nullable

@Component
public class MemberService {

    @Autowired
    public void setMemberService(@Nullable MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

만약 memberRepository가 등록된 스프링 빈이 아니라면 null이 입력된다.

 

(3) Optional<T>

@Component
public class MemberService {

    @Autowired
    public void setMemberService(Optional<MemberRepository> memberRepository) {
        this.memberRepository = memberRepository;
    }
}

만약 memberRepository가 등록된 스프링 빈이 아니라면 Optional.empty가 입력된다.

 

 


@Autowired 는 기본적으로 타입으로 조회하기 때문에 스프링 컨테이너에 같은 타입의 스프링 빈이 두개라면 NoUniqueBeanDefinitionException 이 발생한다.

 

 

이를 해결하는 세 가지 방법은 다음과 같다.

(1) @Autowired는 타입으로 조회한 후 스프링 컨테이너에 같은 타입의 스프링 빈이 여러개라면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭한다. 즉, 필드 이름과 파라미터 이름을 빈 이름으로 변경하면 특정 스프링 빈이 주입된다.

 

(2) 빈 등록 시 @Qualifier를 설정하고, 의존관계 주입 시에도 @Qualifier를 붙여준다.

@Component
@Qualifier("memoryMemberRepository")
public class MemberRepository {
   ...
}


@Component
public class MemberService {

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

 

(3) 같은 타입의 스프링 빈이 두 개일 때 의존 자동주입 할 스프링 빈에 @Primary 애노테이션을 추가한다. 

 

 

※ @Qualifier가 @Primary 보다 우선순위가 높다.

 

 


[ 4 ] lombok

자바의 애노테이션 프로세서는 컴파일 시점에 미리 정의한 애노테이션의 소스코드를 분석하고 처리하며 소스코드(.java)나 바이트코드(.class)를 생성할 수 있다.

롬복은 이러한 애노테이션 프로세스를 활용하며 컴파일 시점에 생성자나 getter/setter, toString 등의 코드를 자동으로 생성해준다.

 

롬복을 활용하여 생성자 주입을 다음과 같이 할 수 있다.

@Service
@RequiredArgsConstructor
public class MemberService {

    private final JpaMemberRepository memberRepository;
    
}

@RequiredArgsConstructor 애노테이션은 final이나 @Notnull 이 붙은 필드의 생성자를 자동으로 생성해준다.

저작자표시 비영리 변경금지 (새창열림)

'Programming > Spring' 카테고리의 다른 글

[Spring] 컴포넌트 스캔  (1) 2023.03.24
[Spring] 싱글톤 컨테이너  (1) 2023.03.15
[Spring] 스프링 컨테이너(Spring Container)  (1) 2023.03.07
    'Programming/Spring' 카테고리의 다른 글
    • [Spring] 컴포넌트 스캔
    • [Spring] 싱글톤 컨테이너
    • [Spring] 스프링 컨테이너(Spring Container)
    TaBo
    TaBo

    티스토리툴바