📌 Spring에서 static 키워드를 지양해야 하는 이유
Java를 사용할 때 static 키워드는 클래스 레벨에서 공유되는 변수 또는 메서드를 정의할 때 자주 사용된다. 대표적으로 static 메서드는 객체 생성 없이 호출할 수 있고, static 변수는 클래스 로딩 시 메모리에 올라가 하나의 값만을 공유하게 된다.
하지만 Spring Framework에서는 이러한 static 사용이 프레임워크의 철학 및 동작 방식과 충돌하며, 불필요하거나 문제가 될 수 있다.

1. Spring은 IoC 기반 프레임워크
• 객체 생성, 생명주기 관리, 의존성 연결 등을 개발자가 아닌 Spring 컨테이너가 제어한다.
• 즉, 객체 인스턴스는 컨테이너가 주입하고 관리해야 하며, 필요한 구성은 모두 빈 단위로 주입 가능한 형태여야 한다.
2. static은 클래스 자체가 제어 주체가 됨
• static 필드나 메서드는 객체 인스턴스와 무관하게 클래스 로딩 시점에 메모리에 올라간다.
• 이는 Spring이 개입하거나 제어할 수 없기 때문에, IoC의 통제를 벗어난 구조가 된다.
즉, Spring은 인스턴스 단위의 제어를 기본으로 하고, static은 클래스 단위의 제어이므로 철학과 구조가 충돌한다.
1. Spring Bean은 싱글톤으로 관리된다 🔍
Spring에서는 기본적으로 Bean이 싱글톤 범위 @Scope("singleton")로 관리된다. 즉, 서비스 클래스의 인스턴스는 애플리케이션 시작 시 한 번 생성되며, 그 인스턴스를 모든 요청에서 공유하게 된다.
@Service
public class MyService {
private final Map<String, Object> cache = new ConcurrentHashMap<>();
}
처럼 클래스 내 인스턴스 필드를 사용해도, 이는 사실상 애플리케이션 전체에서 공유되는 상태로 작동한다.
굳이 static으로 선언하지 않아도 캐시 등 공유 상태 관리가 가능하다.
2. static은 의존성 주입(Dependency Injection)에 제약을 준다 ⚠️
Spring은 의존성 주입(DI) 을 통해 객체 간의 결합도를 낮추고 유연한 아키텍처를 제공한다.
하지만 static 필드는 클래스 로딩 시점에 초기화되므로 Spring의 라이프사이클과 맞지 않아 다음과 같은 의존성 주입이 불가능하다.
// 값 주입 불가
@Value("${custom.value}")
private static String configValue;
// 의존성 주입 불가
@Autowired
private static SomeDependency someDependency;
이러한 경우 NullPointerException 혹은 주입되지 않은 상태로 운영 중 예외가 발생할 수 있다.
Spring의 DI 컨테이너와 static은 근본적으로 상호 운용이 어렵다.
3. 테스트 및 확장성에 불리하다 🧪
static 필드나 메서드는 전역 상태를 가지므로 단위 테스트에서 상태 격리가 어렵고, 테스트 간 side effect가 발생할 수 있다.
또한 @MockBean, @SpyBean 등을 통한 주입도 어렵기 때문에 확장성과 테스트 가능성(Testability) 이 크게 저하된다.
4. 공식 권장 사항: static 사용 자제 📛
Spring 공식 문서에서도 직접적으로 “static을 사용하지 말라”고 표현하지는 않지만, 다음과 같은 원칙을 강조한다.
Spring은 객체 지향 기반 설계를 전제로 한 프레임워크이며, 객체 간의 관계를 IoC 컨테이너를 통해 구성한다.
정적 접근 방식보다 의존성 주입을 통한 유연한 구조가 권장된다.
Introduction to the Spring IoC Container and Beans :: Spring Framework
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) principle. Dependency injection (DI) is a specialized form of IoC, whereby objects define their dependencies (that is, the other objects they work with) only through
docs.spring.io
즉, static을 사용한 전역 접근 방식은 Spring의 핵심 철학인 IoC(Inversion of Control), DI(Dependency Injection) 과 어긋난다.
결론: Spring에서는 static 대신 DI와 Bean의 특성을 활용하자 ✅
| 구분 | static 사용 | Spring Bean 사용 |
| 라이프사이클 | JVM 클래스 로딩 시점 | Spring Context 시작 시 |
| 주입 가능 여부 | 불가능 | @Autowired, @Value 등 가능 |
| 테스트 용이성 | 낮음 | 높음 (@MockBean, @SpyBean) |
| 공유 상태 관리 | 가능 | 가능 (싱글톤 특성 이용) |
Spring에서는 객체 중심의 설계가 기본이며, 전역 상태를 관리하고 싶다면 Spring Bean 싱글톤 범위, ApplicationContext, 캐시 컴포넌트(ex. @Cacheable), 스레드로컬 등의 방법을 고려하는 것이 적절하다.
💡상수 정의나 공용 유틸리티 메서드처럼 상태를 저장하지 않고 객체 주입이 필요 없는 경우에는 static 사용이 가능하다.
Spring에서 static을 사용하지 않아도 Bean 간 상태 공유가 가능하다는 점을 잘 이해하면 유용하게 사용할 수 있다.
특히 Map<String, Object> 같은 자료구조를 서비스 클래스 내부에서 필드로 선언하고 애플리케이션 전반에 걸쳐 캐시처럼 사용할 수 있다는 점은 Spring의 싱글톤 Bean 특성을 잘 보여주는 사례이다.
'🍃SpringFramework' 카테고리의 다른 글
| [SpringFramework] Data 변경을 감지하여 실시간 정보 제공하기 (0) | 2025.06.15 |
|---|---|
| [SpringFramework] 서비스 중인 WAS 트러블슈팅 (with. Spring) (0) | 2024.12.09 |
| [SpringFramework] Filter로 XSS 취약점 대응하기 (0) | 2024.07.04 |