다양한 의존관계 주입 방법
- 생성자 주입
- 수정자 주입(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 버전부터는 기본으로 제공하고 있다.
- 자세한 설치 방법은 아래를 참조한다.
자동 의존관계로 조회하는 빈이 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)를 처리할 때 주로 사용된다.
- 데이터베이스 연결이나 공통 로그 처리 처럼 업무 로직을 지원하기 위한 하부 기술이나 공통 기술들이다.
- 기술 지원 로직은 업무 로직과 비교해서 그 수가 매우 적고 보통 애플리케이션 전반에 걸쳐서 광범위한 영향을 미친다.
- 문제가 발생했을 때 위치 파악은 커녕 적용이 잘 되고 있는지 조차 파악하기 어려운 경우가 많다.
- 이런 경우에는 가급적 수동 빈 등록을 사용해서 명확하게 들어내는 것이 좋다.
해당 글은 인프런 > 스프링 핵심 원리 기본편(김영한)강의를 참고하여 작성하였습니다.
'기초이론 > Spring' 카테고리의 다른 글
[인프런]스프링 핵심원리 기본편_빈 스코프 (0) | 2022.12.11 |
---|---|
[인프런]스프링 핵심원리 기본편_빈 생명주기 콜백 (0) | 2022.12.08 |
[인프런]스프링 핵심원리 기본편_컴포넌트 스캔 (0) | 2022.11.30 |
[인프런]스프링 핵심원리 기본편_싱글톤 컨테이너 (0) | 2022.11.28 |
[인프런]스프링 핵심원리 기본편_스프링 컨테이너와 스프링 빈(스프링 빈 설정 메타 정보 - BeanDefinition) (0) | 2022.11.06 |