Bean 생명주기
🔹 생명주기와 콜백이란?
스프링은 객체(빈)를 생성하고 관리합니다 이 과정에서 초기화하거나 소멸할 때 자동으로 호출되는 메서드들을 지정할 수 있습니다 이게 바로 콜백(callback) 개념
✅ InitializingBean, DisposableBean 인터페이스
- InitializingBean
- 빈이 생성되고 의존성 주입까지 끝나면 호출됨
- 초기 설정 코드 넣을 수 있음
- DisposableBean
- 스프링 컨테이너가 종료되기 전에 호출됨
- 정리 작업(예: 연결 닫기 등)에 사용
@Component
public class MyBean implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("빈 초기화: afterPropertiesSet()");
}
@Override
public void destroy() throws Exception {
System.out.println("빈 소멸: destroy()");
}
}
✅ @Bean 속성으로 초기화/소멸 메서드 지정
@Bean(initMethod = "init", destroyMethod = "cleanup")
public MyService myService() {
return new MyService();
}
- init()은 빈이 생성된 후 실행
- cleanup()은 컨테이너 종료 시 실행
✅ @PostConstruct, @PreDestroy 애너테이션
- 더 간단하고 표준적인 방식!
- 클래스 안에 메서드를 정의해두면, 스프링이 알아서 호출해줍니다.
@Component
public class MyBean {
@PostConstruct
public void init() {
System.out.println("초기화: @PostConstruct");
}
@PreDestroy
public void destroy() {
System.out.println("소멸: @PreDestroy");
}
}
✅ Bean Scope (빈의 범위)
- 스프링 빈이 언제 생성되고 얼마나 오래 살아있는지 설정하는 것
- 가장 자주 쓰는 것만 정리하면:
스코프 설명
| singleton | 스프링 컨테이너에 딱 하나만 존재 (기본값) |
| prototype | 요청할 때마다 새 객체 생성 |
| request | HTTP 요청마다 새 빈 생성 (웹 전용) |
| session | HTTP 세션마다 하나의 빈 사용 (웹 전용) |
@Component
@Scope("prototype")
public class MyBean {
public MyBean() {
System.out.println("MyBean 인스턴스 생성!");
}
}
🚨 API 예외처리
✅ @ExceptionHandler
- 컨트롤러에서 예외가 발생했을 때 처리할 메서드 지정
- 예외 유형별로 다양한 처리가 가능
@RestController
public class MyController {
@GetMapping("/test")
public String test() {
throw new IllegalArgumentException("잘못된 입력!");
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgument(Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
}
✅ @ControllerAdvice
- 예외 처리를 공통으로 모아서 작성 가능
- 여러 컨트롤러에서 예외가 발생했을 때 한 곳에서 처리 가능!
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("오류 발생: " + e.getMessage());
}
}
⚠️ @RestControllerAdvice란?
✅ 정의
- @ControllerAdvice + @ResponseBody의 조합힙니다
- 주로 REST API에서 전역 예외 처리를 할 때 사용합니다.
- 반환값이 JSON 형태로 자동 변환되기 때문에, 프론트엔드와의 통신 시에 유용합니다
✅ 차이점: @ControllerAdvice vs @RestControllerAdvice
항목 @ControllerAdvice @RestControllerAdvice
| 반환 타입 | 뷰(View) or JSON (선택) | 항상 JSON (자동으로 @ResponseBody 적용) |
| 사용 환경 | 웹 페이지 기반 MVC 앱 | REST API 기반 앱 |
✅ 예제: 전역 예외 처리기
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Map<String, String>> handleIllegalArgument(IllegalArgumentException ex) {
Map<String, String> error = new HashMap<>();
error.put("error", "잘못된 요청입니다.");
error.put("message", ex.getMessage());
return ResponseEntity.badRequest().body(error);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, String>> handleAll(Exception ex) {
Map<String, String> error = new HashMap<>();
error.put("error", "서버 오류 발생");
error.put("message", ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
}
- 예외가 발생하면 JSON 형태로 에러 메시지를 반환해줍니다.
- Map으로 커스터마이징된 에러 메시지를 구성할 수 있습니다
✅ 실전 팁
- 프론트엔드와 협업할 때, 에러 메시지를 통일된 형식으로 전달하기 위해 @RestControllerAdvice 사용을 추천합니다.
- 실제 서비스에서는 예외 응답 형식을 별도의 클래스(ErrorResponse)로 만들어서 사용하기도 합니다.