스프링 프레임워크를 사용하다 보면 **의존성 주입(Dependency Injection, DI)**이라는 말을 자주 듣게 됩니다. 의존성 주입은 객체 간의 의존 관계를 스프링이 대신 관리해주는 것을 의미하는데요, 이 과정을 효율적으로 하기 위해 final과 @RequiredArgsConstructor를 많이 사용합니다. 이 글에서는 이 두 가지 키워드가 무엇인지, 왜 사용하는지, 그리고 롬복(Lombok) 없이도 의존성을 주입하는 방법까지 알아보겠습니다.
1. final 키워드는 무엇인가요?
final은 자바에서 변수를 한 번만 초기화하고, 이후에는 변경할 수 없게 만드는 키워드입니다. 이 키워드를 사용하면 다음과 같은 장점이 있습니다:
- 변경 방지: 해당 변수가 의도치 않게 변경되는 것을 방지합니다.
- 안정성: 코드의 안정성을 높여줍니다. 예를 들어, 프로그램이 실행되는 동안 서비스가 특정 리포지토리를 잘못된 다른 리포지토리로 변경되는 실수를 막을 수 있습니다.
2. @RequiredArgsConstructor란?
@RequiredArgsConstructor는 롬복(Lombok) 라이브러리에서 제공하는 애너테이션입니다. 이 애너테이션은 필수 생성자를 자동으로 만들어 줍니다. 여기서 필수 생성자란, final로 선언된 모든 멤버 변수를 초기화해주는 생성자를 말합니다.
예를 들어, 다음과 같은 코드가 있다고 가정해봅시다:
@Service
public class UserService {
private final UserRepository userRepository;
// @RequiredArgsConstructor가 이 생성자를 자동으로 만들어줍니다.
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
위 코드에서 @RequiredArgsConstructor를 사용하면 생성자를 따로 작성하지 않아도 다음과 같이 자동으로 생성자를 만들어줍니다:
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
}
3. 왜 final과 @RequiredArgsConstructor를 함께 사용할까요?
3-1. 의존성의 변경 방지
final 키워드를 사용하면 userRepository가 한 번 초기화된 후에는 변경될 수 없기 때문에, 서비스 클래스가 안정적으로 리포지토리를 사용할 수 있습니다.
3-2. 코드 간결화
@RequiredArgsConstructor를 사용하면 생성자를 자동으로 만들어주기 때문에 코드가 간결해지고, 생성자를 직접 작성하는 실수를 방지할 수 있습니다.
3-3. 의존성 주입(DI)의 편리성
스프링은 서비스 클래스의 생성자를 통해 리포지토리 같은 의존성을 주입합니다. @RequiredArgsConstructor는 필요한 생성자를 자동으로 생성하므로, 의존성 주입이 매우 간편해집니다.
4. 롬복 없이 의존성 주입하기
롬복 없이도 의존성 주입을 할 수 있습니다. 여기서는 생성자 주입과 필드 주입 방법을 소개하겠습니다.
4-1. 생성자 주입
롬복을 사용하지 않고, 생성자를 직접 작성하여 의존성을 주입하는 방법입니다.
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserRepository userRepository;
// 생성자를 직접 작성하여 의존성 주입
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found"));
}
}
장점:
- 의존성이 명확하게 드러나서 코드의 가독성이 높아집니다.
- final 키워드를 사용하여 의존성 변경을 방지할 수 있습니다.
단점:
- 의존성이 많은 경우 생성자가 길어질 수 있습니다.
4-2. 필드 주입
스프링의 @Autowired 애너테이션을 사용하여 필드에 직접 의존성을 주입하는 방법입니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
// 필드 주입
@Autowired
private UserRepository userRepository;
public User findUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found"));
}
}
장점:
- 코드가 간결합니다.
단점:
- final 키워드를 사용할 수 없어, 주입된 의존성이 변경될 수 있는 가능성이 있습니다.
- 테스트가 어려워질 수 있습니다.
5. 어떤 방법을 사용할까요?
생성자 주입 권장
- 생성자 주입은 의존성이 명확하게 드러나고, 테스트가 용이하며, final 키워드와 함께 사용할 수 있어 가장 권장되는 방법입니다.
- @RequiredArgsConstructor는 이러한 생성자 주입을 자동으로 생성해주는 도구일 뿐, 생성자 주입 자체의 이점을 대체하지 않습니다.
필드 주입은 피하기
- 필드 주입은 코드가 간결해 보일 수 있지만, 주입된 객체가 변경될 수 있는 위험이 있고, 테스트 시 주입을 직접적으로 할 수 없어 권장되지 않습니다.
6. 결론
final과 @RequiredArgsConstructor를 사용하면 코드가 더욱 안정적이고 간결해집니다. 의존성 주입 과정에서 실수를 방지하고, 서비스 클래스가 필요한 의존성을 안전하게 보장받을 수 있습니다. 롬복을 사용할 수 없는 경우에는 생성자 주입을 통해 동일한 효과를 얻을 수 있습니다.
이제 여러분도 final, @RequiredArgsConstructor, 그리고 생성자 주입을 활용해 코드의 품질을 한 단계 업그레이드해 보세요!
끝.
'Spring' 카테고리의 다른 글
MSA(마이크로서비스 아키텍처) vs 모놀리식 아키텍처 비교 (0) | 2025.01.09 |
---|---|
[Spring; 스프링] 직렬화와 역직렬화: Jackson ObjectMapper와 스프링부트에서의 활용 (0) | 2024.09.23 |
[Spring; 스프링] JAR , WAR, EAR 차이점 및 특징 (0) | 2024.02.01 |
[Spring; 스프링] Spring MVC 자동구성 제어 / WebMvcConfigurer vs WebMvcConfigurationSupport / Swagger (0) | 2024.01.05 |
[Spring; 스프링] Spring Boot Configuration Processor 란? (feat. 메타데이터; Metadata) (0) | 2023.12.18 |