본문 바로가기

기초이론/Spring

[인프런]스프링 핵심원리 기본편_의존관계 자동주입

다양한 의존관계 주입 방법

  • 생성자 주입
  • 수정자 주입(setter 주입)
  • 필드 주입
  • 일반 메서드 주입

생성자 주입

  • 생성자를 통해서 의존 관계를 주입받는 방법이다.
  • 생성자 호출 시점에 딱 1번만 호출되는 것이 보장된다.
  • 즉, 한번 코드를 짠 후에 변경되지 않는다.
  • 이러한 특징으로 인해 불변, 필수 의존관계에 주로 사용한다.
  • 생성자가 1개만 있으면 @Autowired를 생략해도 자동으로 주입된다. (스프링 빈에만 적용된다.)

생성자 주입 사용 이유

  • 과거에는 수정자 주입과 필드 주입을 많이 사용했지만, 최근에는 스프링을 포함한 DI 프레임워크 대부분이 생성자 주입을 권장한다.
  • 일반적으로 생성자 주입 방식을 사용하고, 옵션이 필요한 경우에만 수정자 주입을 선택하는 방식으로 사용하는게 좋다.
  • 생성자 주입 방식은 프레임워크에 의존하지 않고 순수한 자바 언어의 특징을 잘 살리는 방법이다.
  • 그 이유는 아래와 같다.

1. 불변

  • 대부분의 의존관계 주입은 한번 일어나면 애플리케이션 종료까지 의존관계를 변경할 일이 없다.
  • 대부분의 의존관계는 보통 애플리케이션 종료 전까지 변하면 안된다.
  • 수정자 주입을 사용하면 setXxx 메소드를 public 으로 열어두어야 한다.
  • 그런데 변경하면 안되는 메소드를 열어두는 것은 좋은 설계가 아니다.
  • 생성자 주입은 객체를 생성할 때 딱 1번만 호출되며 이후로 호출되는 일이 없다. 즉, "불변"하다.

2. 누락

  • 생성자 주입을 사용하면 주입 데이터를 누락했을 때 컴파일 오류가 발생한다.
  • IDE에서 바로 어떤 값을 필수로 주입해야 하는지 알 수 있다.

3. final 키워드

  • 생성자 주입 방식만 final 키워드를 사용할 수 있다.
  • 그래서 생성자에서 혹시라도 값이 설정되지 않는 오류를 컴파일 시점에 막아준다.

수정자 주입(setter 주입)

  • setter 라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존관계를 주입하는 방법이다.
  • 선택과 변경 가능성이 있는 의존관계에 주로 사용한다.
  • 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법이다.
  • @Autowired의 기본 동작은 주입할 대상이 없으면 오류가 발생한다.
  • 주입할 대상이 없어도 동작하게 하려면 ' @Autowired(required = false) ' 로 지정하면 된다.
  • 자바에서는 과거부터 필드의 값을 직접 변경하지 않고 setXxx, getXxx 라는 메서드를 통해서 값을 읽거나 수정하는 규칙을 만들었는데, 이것이 자바빈 프로퍼티 규약이다.

필드 주입

  • 필드에 바로 주입하는 방식이다.
  • 코드가 간결하지만 외부에서 변경이 불가능하기에 테스트가 힘들다는 치명적인 단점이 있다. 
  • DI 프레임워크가 없으면 아무것도 할 수 없다.
  • 사용을 지양한다.

일반 메서드 주입

  • 일반 메서드를 통해서 주입받을 수 있다.
  • 한번에 여러 필드를 주입받을 수 있다.
  • 일반적으로 잘 사용하지 않는다.

옵션 처리

  • 주입할 스프링 빈이 없어도 동작해야 할 때가 있다.
  • @Autowired만 사용하면 required 옵션의 기본값이 true로 되어있어 자동 주입 대상이 없으면 오류가 발생한다.

자동 주입 대상의 옵션 처리

  • @Autowired(required = false) : 자동으로 주입할 대상이 없으면 수정자 메소드 자체가 호출이 되지 않는다.
  • org.springframework.lang.@Nullable : 자동으로 주입할 대상이 없으면 null이 입력된다.
  • Optional<> : 자동 주입할 대상이 없으면 Optional.empty 가 입력된다.

롬복

  • getter, setter, 생성자 등 Java 라이브러리로 반복되는 메소드를 작성하는 코드를 줄여주는 코드 다이어트 라이브러리다.
  • @RequiredArgsConstructor : final이 붙은 생성자를 만들어준다.
  • @getter, @setter : getter, setter 코드 없이 사용할 수 있다.

롬복 설치 및 적용법

  • 롬복은 build.gradle에 라이브러리와 환경을 추가한 후에 적용할 수 있다.
  • 인텔리제이에서는 File > Settings > Plugins에서 lombok 입력 후, lombok를 설치한다.
  • 단, 2020.3 버전부터는 기본으로 제공하고 있다.
  • 자세한 설치 방법은 아래를 참조한다.

https://leeys.tistory.com/27

 

Intellij 롬복(Lombok) 설치 및 설정 방법

Intellij에서 Lombok 설정 방법에 대해 알아보겠습니다. Lombok은 자바 클래스에서 자주 사용하는 getter, setter 등을 어노테이션을 사용하여 반복되는 작업을 생략하도록 빌드 시점에 자동으로 생성해

leeys.tistory.com

 


자동 의존관계로 조회하는 빈이 2개 이상일 때

  • @Autowired는 타입으로 조회한다.
  • 타입으로 조회하기 때문에, 선택된 빈이 2개 이상일 때에 문제가 발생한다.
  • 2개 이상에 @Component가 설정된 상태라면 NoUniqueBeanDefinitionException 오류가 발생한다.
  • 해당 오류메시지는 하나의 빈을 기대했는데 여러개가 발견되었다는 의미이다.
  • 하위 타입으로 지정해서 해결할 수도 있지만, 이는 DIP를 위배하고 유연성이 떨어진다.
  • 또한 이름만 다르고 동일한 타입의 스프링 빈이 2개 있을 때에 해결이 되지 않는다.

해결방법

1. @Autowired 필드명

  • @Autowired는 타입 매칭을 시도하고, 이 때 여러 빈이 있으면 필드 혹은 파라미터 이름으로 빈 이름을 추가 매칭한다.
  • 즉, 타입이 동일하면 필드명 또는 파라미터명으로 빈 이름을 매칭한다.

2. @Qualifier

  • @Qualifier는 추가 구분자를 붙여주는 방식이다.
  • ex) @Qualfier("plusName")
  • 주입 시 추가적인 방법을 제공하는 것이지 빈 이름을 변경하는 것이 아니다.
  • @Qualifier 끼리 매칭한다.

3. @Primary

  • 우선순위를 지정하는 방법이다.
  • @Autowired 시에 여러 빈이 매칭되면 @Primary가 우선권을 가진다.

스프링은 자동보다는 수동, 넓은 범위보다는 좁은 범위가 우선권을 가진다. 즉, 더 세세하게 정해주는 @Qualfier가 @Primary 보다 우선 순위가 높다.


어노테이션 직접 만들기

  • @Qualfier("AA") 에서 AA는 문자이다. 문자는 컴파일 시 타입 체크가 안된다.
  • 이를 해결하기 위해서 어노테이션을 직접 만드는 방법이 있다.

조회한 빈이 모두 필요할 때

  • 여러 개의 빈을 조회하고 싶을 때에는 List와 Map을 사용한다.

자동, 수동의 올바른 실무 운영 기준

  • 기본적으로는 자동을 사용하자.
  • 스프링이 나오고 점점 자동을 선호하는 추세이다.
  • 스프링은 계층에 맞추어 일반적인 애플리케이션 로직을 자동으로 스캔할 수 있도록 지원한다.
  • 또한 스프링 부트로 넘어오면서 컴포넌트 스캔을 기본으로 사용하고, 스프링 부트의 다양한 스프링 빈들도 조건이 맞으면 자동으로 등록하도록 설계되었다.

애플리케이션 로직

애플리케이션은 크게 업무 로직과 기술 지원 로직으로 나눌 수 있다.

 

업무 로직 빈

  • 웹을 지원하는 컨트롤러, 핵심 비즈니스 로직이 있는 서비스, 데이터 계층의 로직을 처리하는 리포지토리 등이 모두 업무 로직이다.
  • 보통 비즈니스 요구사항을 개발할 때 추가되거나 변경된다. 
  • 업무 로직은 숫자가 매우 많고 한번 개발하려면 컨트롤러, 서비스, 레파지토리 처럼 어느정도 유사한 패턴이 있다.
  • 이런 경우 자동 기능을 적극적으로 사용하는 것이 좋다.
  • 보통 문제가 발생해도 어떤 곳에서 문제가 발생했는지 명확하게 파악하기 쉽다.

기술 지원 빈

  • 기술적인 문제나 공통 관심사(AOP)를 처리할 때 주로 사용된다.
  • 데이터베이스 연결이나 공통 로그 처리 처럼 업무 로직을 지원하기 위한 하부 기술이나 공통 기술들이다.
  • 기술 지원 로직은 업무 로직과 비교해서 그 수가 매우 적고 보통 애플리케이션 전반에 걸쳐서 광범위한 영향을 미친다.
  • 문제가 발생했을 때 위치 파악은 커녕 적용이 잘 되고 있는지 조차 파악하기 어려운 경우가 많다.
  • 이런 경우에는 가급적 수동 빈 등록을 사용해서 명확하게 들어내는 것이 좋다.

해당 글은 인프런 > 스프링 핵심 원리 기본편(김영한)강의를 참고하여 작성하였습니다.