스프링을 공부하다 보면 가장 처음 마주치는 어노테이션 중 하나가 @Configuration 입니다.
처음엔 "설정 클래스인가 보다" 하고 넘어가기 쉬운데 이 어노테이션이 하는 일과 쓰는 이유를 정확히 이해하면 스프링 프레임워크에 대한 이해가 더 깊어질 수 있을 것 같아 글을 작성합니다.
이번 글에서는 @Configuration의 역할, @Component와의 차이점, 그리고 실제로 언제 왜 써야하는지를 예시와 함께 정리해보겠습니다.
@Configuration의 정체
@Configuration
public class AppConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = objectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeatuer.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
@Configuration이 붙은 클래스는 스프링이 설정 클래스로 인식합니다. 내부에 정의된 @Bean 메서들은 객체를 생성하고, 반환된 객체는 스프링 컨테이너에 빈으로 등록됩니다.
하지만 여기서 중요한 점은 Spring은 @Configuration이 붙은 클래스를 프록시 객체(CGLIB)로 감싸서 싱글톤을 보장해준 다는 것입니다. 즉 여러 개의 @Bean 메서드에서 동일한 빈을 참조하더라도 항상 같은 인스턴스를 주입하게 됩니다.
반면 @Component만 붙인 경우에는 프록시 적용이 되지 않기 떄문에 @Bean 메서드를 호출하면 객체가 매번 생성되어 싱클톤이 꺠질 수 있습니다.
그럼 이걸 왜 쓸까?
1. 외부 라이브러리 객체를 빈으로 등록하고 싶을 때
라이브러리에서 제공하는 클래스는 우리가 직접 @Component 를 붙일 수 없습니다. 이런 객체를 스프링 컨테이너에 등록하고 싶을 때 @Bean 을 사용해야 합니다.
@Configuration
public class RedisConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}
@Service
public class WeatherService {
private final RestTemplate restTemplate;
public WeatherService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getWeather(String city) {
String url = "https://api.weather.com/wheater?city=" + city;
return restTemplate.getForObject(url, String.class);
}
}
2. 커스터마이징한 ObjectMapper를 등록하고 싶을 때
objectMapper를 그대로 쓰면 LocalDateTime 같은 타입이 timestamp로 출력되는데, 이걸 ISO 형식으로 바꾸고 싶다면?
@Configuration
public class AppConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = objectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeatuer.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
@Service
public class JsonService {
private final ObjectMapper objectMapper;
public JsonService(ObjectMapper mapper) {
this.objectMapper = mapper;
}
public String toJson(Object obj) throws JsonProcessingExcpetion {
return objectMapper.wirteValueAsString(obj);
}
}
전체 흐름 요약 순서도
Application 시작
↓
@ComponentScan으로 HttpClientConfig 감지
↓
@Configuration 감지 -> restTemplate() 메서드 실행
↓
RestTemplate 객체 생성 및 커스텀 설정 적용
↓
Spring Container에 RestTemplate 빈으로 등록
↓
서비스 클래스에서 생성자 주입으로 사용
@Configuration은 단순히 설정 파일 이상의 역할을 합니다.
- 객체 구성과 의존관계를 명확하게 설정하고 싶을 때
- 외부 라이브러리 객체를 스프링 빈으로 등록할 때
- 환경에 따라 다른 설정을 유연하게 적용하고 싶을 때
'Back-End > Spring' 카테고리의 다른 글
| Spring AOP Proxy - SelfInvocation 문제 (0) | 2025.03.17 |
|---|---|
| Spring은 어떻게 객체를 관리할까? (0) | 2025.02.25 |
| Self-Invocation(자기호출) 문제 (0) | 2025.02.25 |
| SpringSecurity Authentication 객체와 Principal 객체 (0) | 2025.01.24 |
| SpringSecurity + JWT를 활용한 로그인 (0) | 2025.01.23 |