@RequiredArgsConstructor
개념
- final 필드나 @Nonnull 애노테이션이 붙은 필드만을 파라미터로 받는 생성자를 자동으로 생성해줌(기본생성자 생성 X)
- Lombok 라이브러리에서 제공하는 애노테이션 중 Java 클래스에서 필수 필드를 초기화하는 생성자를 자동으로 생성해주는 기능
# 사용예시
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;
private String optionField;
}
위 코드에서 @RequiredArgsConstructor 는 생성자를 다음과 같이 자동으로 만들어준다.
public MemberService(MemberRepository memberRepository, PasswordEncoder passwordEncoder) {
this.memberRpository = memberRepository;
this.passwordEncoder = passwordEncoder;
}
# final & @NonNull 에 대해서 만 생성되는 이유
1. final 필드는 생성시 반드시 초기화 되어야함
2. @NonNull 은 'null 이면 안된다'는 의미
- final 이 아니면 필드 선언만으로 초기화를 강제할 수 없기 때문에 @RequiredArgsConstructor 가 객체 생성 시점에 반드시 값을 넘기도록 강제시킴
예시)
@RequiredArgsConstructor
public class User {
@NonNull
private String name; // final 아님!
}
@RequiredArgsConstructor 사용시 생성자 자동 생성하여 아래와 같이 직접 작성하지 않아도 됨
public User(String name) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
}
this.name = name;
}
보일러플레이트 코드 제거 효과
@RequiredArgsConstructor 사용시 생성자 직접 작성 없이 자동 생성할 수 있기 때문에 불필요한 코드 작성을 피할 수 있다 !
*보일러플레이트 코드(Boilderplate Code)
자주 반복되는 작업이나 패턴을 미리 구현해놓은 코드를 일컫는 말
필드 주입 vs 생성자 주입
# 필드 주입(Field Injection) 방식
@Autowired
private JwtUtil jwtUtil;
- Spring이 리플렉션(Reflection)을 이용해서 객체를 강제로 주입
* 리플렉션 = 자바가 내부적으로 필드에 접근해서 값 넣는 것
# 필드 주입의 문제
문제 설명 테스트 어려움 필드가 private이라 Mock 주입이 어렵고 setter가 없으면 더 어려움 불변성 깨짐 객체 생성 후에도 값을 변경할 수 있음 (final 못 씀) 순환참조 숨김 생성자에 드러나지 않아서 IDE나 컴파일러가 의존성 문제를 못 잡음 명시성이 부족 어떤 의존성을 사용하는지 클래스만 봐선 한눈에 안 들어옴
@Autowired를 필드에 붙이면 주입 시점, 방식이 불명확함
필드 주입 방식
@RequiredArgsConstructor
@Slf4j
@Tag(name = "Account", description = "계정 관련 API")
@RestController
public class AccountController {
@Autowired
private AccountService accountService; // <- 필드 주입
}
- final이 아니기 때문에
누군가 코드 중간에 바꿔치기 할 수 있음 (accountService = new Something() 같은 거) - 생성자에 없어서 IDE나 컴파일러가 의존성을 체크 못 함
→ 빠뜨려도 오류 안 나고 런타임 에러 발생 (NullPointerException) - 테스트 불편
- private이라서 Mockito 같은 걸로 바꿔끼우려면 리플렉션 필요함
- 주입 시점도 불명확해서 테스트에 복잡성 추가
생성자 주입 방식
@RequiredArgsConstructor
@RestController
public class AccountController {
private final AccountService accountService; // 생성자로 주입됨!
}
- final이라 바꿀 수 없음 (불변)
- @RequiredArgsConstructor가 생성자 만들어줌
- 스프링이 생성자 보고 자동으로 주입해줌
- IDE가 의존성 빠졌는지 바로 감지 가능!
# 요약
항목 | @Autowired 필드 주입 | 생성자 주입 (@RequiredArgsConstructor) |
선언 방식 | 필드에 @Autowired 붙임 | 생성자에서 받음 (final + 생성자 자동 생성) |
장점 | 코드 간결 | 불변성, 테스트 용이, 명확한 의존성 |
단점 | 테스트 어려움, 프록시 오류 가능성 | 약간의 boilerplate 있음 (Lombok으로 해결 가능) |
추천 여부 | ❌ 비추천 (Spring 공식에서도 지양) | 강력 추천 |
주입 시점 | 객체 생성 후 주입 (따로) | 객체 생성 시점에 주입 (한번에) |
Null 가능성 | 있음 (초기화 전에 쓰면 null 가능) | 없음 (생성자에서 반드시 초기화) |
불변성 보장 | 없음(final 아님) | 있음(final 필드) |
테스트 편의성 | 어려움(리플렉션 등 필요) | 쉬움 (생성자 통해 바로 주입 가능) |
- final, @NonNull 필드는 반드시 생성자로 초기화해야 하므로 @RequiredArgsConstructor를 사용하면 편함
- @Autowired 필드 주입은 테스트, 유지보수에서 불리하고 요즘은 거의 안 씀
Spring에서 지원하는 의존성 주입 방식 3가지
1. 필드 주입
@Autowired private A a;
2. 생성자 주입 - 가장 많이 쓰임
public A(A a) { this.a = a; }
3. 세터 주입
@Autowired public void setA(A a) { this.a = a; }
`@RequiredArgsConstructor` 에 대해서 완전하게 이해지못하고 그냥 있어야한다는 사실만 알고 공식처럼 쓰며 `@Autowired` 와 같이 사용하고 있었다
이번 학습을 통해 명확하게 이해하고 기존 코드를 리펙터링 할 수 있는 기회가 되었다 !!
'Backend > Spring & Spring Boot' 카테고리의 다른 글
스프링 롬복 인식 실패 문제 해결 (4) | 2025.06.16 |
---|---|
Spring Security - SimpleGrantedAuthority, UserDetails, UserDetailsService (0) | 2025.05.29 |
Spring Security 의 초기 username 설정 위치 (0) | 2025.04.29 |
AOP 동작 방식 (0) | 2025.02.04 |
Spring에서 @Autowired와 static 메서드 사용 시 NullPointException (0) | 2025.01.22 |