카테고리 없음

Spring 심화 3주차 정리(1) (Bean 생명주기, API 예외처리)

404NotFoundMe 2025. 4. 18. 10:41

 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)로 만들어서 사용하기도 합니다.