섹션 8
다양한 의존관계 주입 방법
크게 4가지 방법이 있음
- 생성자 주입
- 수정자 주입(setter 주입)
- 필드 주입
- 일반 메서드 주입
1. 생성자 주입
OrderService의 구현체에 들어가보면, 생성자에 @Autowired가 있다. 스프링쪽에서 이걸 보면, 바로 MemberRepository와 DiscountPolicy를 꺼내서 주입해준다.
- 생성자 호출시점에 딱 1번만 호출되는게 보장됨. -> 두번 호출되는것을 막을 수 있음.
- 불변, 필수 의존관계에 사용됨.
여기서 생성자 호출 이후로 아무도 MemberRepository와 DiscountPolicy를 수정할 수 없다. 즉 얘는 불변임.
* 좋은 개발습관은 한계점과 제약을 적절히 사용하는것. 불변이라는 개념은 정말로 중요하다.
final로 선언했으면 그 값이 Null이 되어선 안된다.
여기서는 final로 선언했으므로 꼭 값을 넣어줘야 한다. 즉 얘는 필수임.
*만약 생성자가 딱 한개만 있다면?? (생성자가 두개 있으면 @Autowired지정해 줘야 함)
아무것도 안 써도 @Autowired붙은 것과 동일하게 취급함.
굿!
2. 수정자 주입(setter주입)
이건 필드값을 바로 수정하기보다는 setter를 통해 수정하게 하는 법인데,
@Autowired를 setter마다 써줘야 한다. 그러면 @Autowired가 걸린 얘들을 주입해준다!
굿
사실 스프링 빈 등록과 DI 관계는 따로 작동한다. 생성자도 의존관계가 일어나지만, setter는 생성자 주입이 조금 특이하다.
생성자의 경우, 객체 생성 시 생성자를 호출해야 한다. 그래서 생성자는 빈 등록할 때 자동주입이 일어난다.
수정자는 그런 경우가 아니기 때문에 DI 때 일어난다. 그래서 1번과 2번의 호출 순서는 다르다.
- 수정자가 있으면 생성자는 굳이 없어도 됨.
- 선택, 변경 가능성 있는 의존관계에 사용 (선택적으로 주입 시 @Autowired(required=false)로 써준다.
- MemberRepository가 빈에 등록이 안되어 있는 상황 등에서 쓸 수 있다. (선택)
- 인스턴스를 바꾸고 싶으면 외부에서 수정자 호출하면 됨. (변경)
*@Autowired의 기본 동작은 주입할 대상이 없으면 오류가 발생한다. 해결하고 싶으면 @Autowired(required=false 쓰기
*자바빈 프로퍼티 규약 : getXXX, setXXX 등의 메서드를 통해 값을 읽거나 수정하는 규칙
3. 필드 주입
이름 그대로 필드에 값을 넣는 것.
이렇게 @Autowired를 객체생성때 붙여주면 된다.
아주 잘 생성됐다. 필드에 의존관계를 바로 넣어주기 때문에 된 것이다.
- 코드가 간결하다.
인텔리제이는 별로 추천하지 않는다고 한다.
- 외부에서 변경이 불가능하다.
- 이렇게 값을 넣으려고 하면 NullPointer에러가 뜬다. 해결하려면 setter를 따로 만들어줘야 한다.
- 결국 fieldInjection을 하고 싶으면 setter를 만들어야 한다. 차라리 setter에 @Autowired하는게 낫다.
- 결국 가급적이면 쓰지말자. 예외는 있다. @Configuration같은 곳에는 써도 됨. 애플리케이션의 코드와 관계없는 경우도.
4. 일반 메서드 주입
말 그대로 아무 메서드에 @Autowired를 쓸 수 있다.
- 한번에 여러 필드를 주입받을 수 있지만, 일반적으로 잘 쓰지는 않는다.
- 스프링 빈이 아닌 일반 자바 객체는 당연히 작동 안한다. 즉, 스프링 컨테이너가 관리하는 스프링빈이어야만 작동한다.
옵션 처리
- 주입할 스프링 빈이 없어도 동작해야 할 때가 있다.
- @Autowired만 쓰면 required옵션이 true이므로 자동주입 대상이 없으면 오류가 뜬다.
- 이를 옵션으로 처리하는 법?
결과는?
1. Autowired(required = false)
자동주입할 대상이 없으면 setter 자체가 호출안됨
setNoBean1 자체가 출력이 안됐음.
2. org.springframework.lang.@Nullable
자동주입할 대상이 없으면 null 이 입력된다.
setNoBean2 는 출력은 되는데, null값이 출력됨
3. Optional<>
자동주입할 대상이 없으면 Optional.empty 이 출력됨
setNoBean3는 출력은 되는데, Optional.empty가 출력됨
- Member는 스프링빈이 아니다.
- @Nullable, Optional은 스프링 전반에 걸쳐서 지원됨.
- 생성자 주입에서 특정 필드에서만 쓰고 싶을 때 쓸 수 있음
생성자 주입을 선택해라!
'불변'
대부분의 의존관계는 어플리케이션 종료까지 변경할 일도 없고, 변경하면 안된다. 수정자 주입을 사용하면, setXX메서드를 public으로 열어놓아야 함. 이는 근데 누군가 수정이 가능해서 좋은 방법은 아니다.
'누락'
프레임워크 없이 순수한 자바 코드를 작성 & 테스트 하는 경우에..
이렇게 하고 테스트를 돌리면 nullPointException error 가 뜸
왜냐.. 얘네 값을 세팅해 줘야 함. 최소한 임의의 dummy repository라도 넣어야 함.
기존 생성자를 지워주고, 임의의 객체를 파라미터로 넣어준다.
임의의 테스트를 만들어줌
- 생성자 주입을 쓰면 final 키워드를 쓸 수 있다. final은 생성할 때 정해지면 안 바뀜. 생성자에서만 값을 넣어줄 수 있다는 뜻.
- 생성자를 만들었는데 값을 넣는 부분을 빼먹을 수도 있는데, 이를 쉽게 발견하는 법은 final으로 선언하는 것이다. 위의 말대로
final은 값이 들어와야 하는데, 값이 없으므로 컴파일 에러로 쉽게 잡을 수 있다.
- 생성자 주입만 final 키워드를 쓸 수 있다.
- 생성자 주입과 수정자 주입을 동시에 쓸 수 있다.
- 필드주입은 안쓰는게 좋다.
* 컴파일 오류가 세상에서 가장 빠르고 좋은 오류다!!
* 어지간하면 생성자 주입을 쓰자. 대부분의 오류가 해결된다.
롬복과 최신 트렌드
요즘 트렌드 -> 롬복
막상 개발해보면 거의 99퍼센트 불변이고, 생성자에 final키워드를 쓰게 된다.
근데 생성자를 만드는 것과 이를 주입하는 코드를 만들기가 번거롭다.
필드 주입처럼 한번에 쓸수 있는법이 있을까?
롬복이라는 라이브러리를 적용해 보자! 롬복은 getter setter등을 생성해준다.
build.gradle를 수정해 준다.
또한 설정에 Annotation Processors를 꼭 켜줘야 한다 꼭!
예제를 하나 만들어주고 실행을 해보면 되는데...
저기....
https://velog.io/@coastby/Spring
여기서 해결해 보자.
나는 두번째 방법인 캐시를 지우고 재시작 하는걸로 해결됐다.
아니 안됐다.
https://small-stap.tistory.com/70
이것도 해봤는데..
gradle 버전조차 확인이 안되는데요?
이걸 따라했는데... 더 망한 느낌
'WINK-(Web & App) > Spring Boot 스터디' 카테고리의 다른 글
[2024-2 Spring Boot 스터디] 조상혁 #6주차 (3) | 2024.12.02 |
---|---|
[2024-2 Spring Boot 스터디] 김아리 #5주차 (0) | 2024.11.28 |
[2024-2 Spring Boot 스터디] 조상혁 #5주차 (2) | 2024.11.27 |
[2024-2 Spring Boot 스터디] 김문기 #5주 (0) | 2024.11.27 |
[2024-2 SpringBoot 스터디] 정호용 #5주차 섹션 6~7 (0) | 2024.11.25 |