1. 들어가며
스프링에서 빈을 주입하는 3가지 방법이 있고, 각각 어떻게 하며, 추천하는 방법은 무엇인지 알아보자.
2. 빈을 주입하는 방법 3가지
보통 Spring 빈 주입은 3가지가 있다.
- 필드 주입
- setter 주입
- 생성자 주입
3. 1) 필드 주입
@Service
public class MemberService {
@Autowired
private MemberRepository memberRepository;
}
필드 주입은 주입하려는 빈을 필드에 설정하고, @Autowired
어노테이션을 단다. 그러면 Spring에서 해당 빈을 외부에서 생성해서 주입(inject)해준다. 단점은 MemberService
를 테스트할 때 필드로 주입된 memberRepository가 강하게~~~ 결합되어 있어서(의존도가 있음) 테스트 할때 어려움이 있다.
4. 2) Setter주입
setter 주입은 어떨까?
public class MemberService {
private MemberRepository memberRepository;
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
setter 주입은 필드 주입에 비해서, setter를 통해서 MemberRepository 말고도 다른 MockMemberRepository와 같은 목객체를 setter로 주입해서 테스트를 할 수 있다. 하지만, 런타임에 리플렉션을 통해서 누군가 해당 레포지토리를 변경할 수 있다는 단점이 있다.
5. 3) 생성자 주입
생성자 주입은 어떨까?
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
생성자 주입은 생성 시점에 해당 Repository가 주입되기 때문에 변경할 수 있는 방법이 없다. 하나 더 나아가자면 final
키워드를 추가함으로써 컴파일 타임에 MemberRepository
까먹지 않고 주입시켜줄 수 있다. 또한, 애초에 MemberService에 대한 테스트를 작성할 때도 Mock객체와 같이 생성자를 통해서 주입가능 하기 때문에(의존도가 약해짐) 테스트 작성에서도 용이하다.
다음과 같이 여러 가지 다양한 구현체(Mock)을 통해서 주입할 수 있다.
// 인프라 구현체를 jdbc로 mock객체를 주입
MemberService memberService = new MemberService(new MockJdbcMemberRepository());
// 인프라 구현체를 h2 인메모리DB로 mock객체를 주입
MemberService memberService = new MemberService(new MockInMemoryMemberRepository());
6. 보너스: Lombok 사용시
3가지 중 생성자 주입이 👍 좋다는 것을 알았다. 실무에서 롬복을 사용하는 경우에 코드를 어떻게 줄일 수 있을까 ?
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
}
@AllArgsConstructor
는 존재하는 필드에 대해서 생성자를 만들어 준다. 이것보다는 @RequiredArgsConstructor
이것을 사용하는 것을 권장한다. 이렇게 하면 코드양이 줄고, 가독성이 올라갔다.
7. ✋ 똑똑한 IntelliJ
보통은 습관적으로 코딩하게 되면 @Autowired
로 필드 주입을 사용하게 된다. 현재 2019.3 버전 IntelliJ를 사용하게 되면 노란색으로 경고 표시가 나오고 필드 주입은 추천하지 않는다고 한다. ⌥ + ↵ (alt + enter) 를 누르면 자동으로 생성자 주입으로 변경해 준다.
8. 정리
- 스프링에서 빈을 주입하는 방법에 대해서 알아봤다. 생성자 주입이 최고다. 이유는 의존도를 낮춤으로써 다양한 의존관계(mock)으로 대체할 수 있기 때문이다.
- 추가로 롬복을 사용하게 된다면, @RequiredArgsConstructor 어노테이션을 통해서 비교적 코드양을 줄일 수 있다.
- 생각해볼 것🤔:: 생성자 주입을 했을때 결국 생성자 필드에 엄청 많은 의존관계를 주입하게 된다면 코드도 지저분해지고 SRP를 지키지 않게 된다. 그러니 MemberService로 시작했지만, MemberUpdateService, MemberOrderService 와 같이 각 비즈니스가 하는 역할을 명확하게 표현할 수 있는 서비스로 나중에 쪼개야 한다. 생성자 주입시, 4개 이상을 넘어가지 않는게 좋은 것 같다!!!
📚 Related Posts
- SpringBoot, MongoDB 시작하기
- Spring Boot 서버 타임존 설정 방법
- SpringBoot CommandLineRunner, ApplicationRunner 초기화 방법
- Jackson, LocalDateTime Serialization, Deserialization 이슈
- Spring Boot, Dockerfile로 이미지 생성, 배포하기
- SpringBoot RabbitMQ 연동하기
- Junit5 정리
- Spring Sentry(에러 트래킹 서비스) 적용하기
- [Spring] 빈 주입하는 방법 && Best Practice
- Thymeleaf 실무에서 자주 사용하는 것들
- Thymeleaf Collection 정보 화면에 렌더링하기
- Spring, JPA를 이용한 REST API 만들기
- [Spring] MultipartFile을 이용한 파일 업로드
- [Spring] 모델 검증(validation)
- [Spring]HandlerMethodArgumentResolver 인터페이스
- [Spring] DispatcherServlet에 대해서 알아보자
- [Spring] MVC 만들어 보기
- [Spring] 메세지 컨버터
- [Spring] MVC 살펴보기
- [Spring] @ConfigurationProperties를 이용해서 properties값들을 클래스로 관리하기
- [Spring] Profile 설정하기
- [Spring] SpringApplication를 통한 코딩
- [Spring Boot] 스프링 부트 3가지 특징
- [Spring] @SpringBootAppllication 어노테이션에 대한 고찰
- [Spring] bean circular dependencies (빈 순환 참조)
- [Spring]Bean에 대해서 알아보자
- SpringBoot, JPA, H2를 이용한 간단한API 작성
- [Spring] Spring Data Common 프로젝트 살펴보기