처음에는 “@Setter는 쓰지 말라고 하던데, 그런데 왜 어떤 코드는 쓰고 어떤 코드는 안 쓰는 거지?” 라는 생각이 들었습니다. 저처럼 의존성 주입은 무조건 생성자 방식이 좋다고 배워왔던 분들에게는 @Setter나 set 메서드의 존재가 헷갈릴 수 있습니다.
하지만 최근 프로젝트를 하면서 설정값을 다루는 @ConfigurationProperties 같은 클래스에서 setter 메서드를 직접 써야 하는 경우가 있었고, 그 이유를 공부하면서 정리가 필요하다고 느껴 이 글을 작성하게 되었습니다.
저처럼 '@Setter=안좋다'라고만 배웠던 분들에게 도움이 되길 바라며, 구체적으로 언제 사용하는지 살펴보겠습니다 😊
❓ 무조건 생성자 주입이 최고 아닌가?
보통 Spring에서는 불변성(immutability) 과 명시적 의존성을 위해 생성자 주입을 권장합니다. 그래서 @Setter는 되도록 쓰지 말라고 배우죠.
그런데, 정말 모든 경우에 Setter는 안 쓰는 게 맞을까요?
사실 그렇진 않습니다.
🔍 설정값 주입에선 왜 Setter를 써야 할까?
예를 들어 application.yml에 이런 설정이 있다고 가정해볼게요
jwt:
secret: abc123
access-token-expiration: 3600
이 설정을 아래처럼 자바 코드에서 받으려면?
@Configuration
@ConfigurationProperties(prefix = "jwt")
@Getter
public class JwtConfig {
private String secret;
private long accessTokenExpiration;
public void setSecret(String secret) {
this.secret = secret;
}
public void setAccessTokenExpiration(long accessTokenExpiration) {
this.accessTokenExpiration = accessTokenExpiration;
}
}
여기서는 Spring이 객체를 생성하고, 내부적으로 setter를 통해 설정값을 주입합니다.
즉, 이 경우에는 생성자 주입을 사용할 수 없고, setter가 반드시 필요합니다.
✅ 이건 우리가 직접 new JwtConfig(...) 하는 게 아니라, Spring이 바인딩을 해주기 때문입니다.
* 바인딩(binding)은
- 어떤 데이터를 자바 객체의 필드에 연결해주는 행위
- 데이터를 객체에 넣는 자동화된 작업
✅ @Setter, set 메서드를 써야 하는 경우 정리
| 상황 | 사용 여부 | 이유 |
| @ConfigurationProperties 로 설정값 바인딩 | ✅ 꼭 필요 | Spring이 객체 생성 후 setter로 값을 주입 |
| DTO 클래스 (조회용, 응답용) | 상황에 따라 ⭕ | 불변성보다는 편의성이 중요할 때 |
| 테스트용 Stub 객체 | 상황에 따라 ⭕ | 빠른 설정과 유연한 조작 목적 |
| 일반 서비스/도메인 클래스 | ❌ 피해야 함 | 생성자 주입으로 불변성, 명시성 확보 |
💡 왜 일반 서비스 코드에선 Setter를 피할까?
- 값이 언제든지 바뀔 수 있어 불변 객체 설계가 어려워짐
- 순환 참조나 테스트의 어려움을 만들 수 있음
- 어떤 의존성이 필수인지 명시적으로 드러나지 않음
그래서 설정값 바인딩처럼 Spring 내부에서 자동으로 값을 넣어주는 특수한 경우가 아니라면, 웬만하면 생성자 주입을 사용하는 게 좋습니다.