Kim-Baek 개발자 이야기

[카카오 면접] 스프링의 예외 처리 본문

개발/Spring

[카카오 면접] 스프링의 예외 처리

김백개발자 2020. 9. 19. 13:02
카카오 면접을 준비하면서, 공부했던 내용을 정리해놓고 다시 기억하기 위한 포스팅

기본 Error Handler

스프링 부트에는 기본적으로 error handler가 들어가 있다.

index페이지가 없을 때, localhost:8080으로 요청 시, 보이는 화면이 기본 error handler가 처리해준 결과이다.

 

@MVC 예외 처리 방법

Error를 테스트 하기 위해 Controller를 만들어준다.
Controller에서 /hello 요청이 왔을 때 Error를 던지게 한다.

SampleException이라는 클래스를 만들어 RuntimeException을 던지도록 해준다.(extends RuntimeException)

그 후, 이 앱에 특화되어 있는 error 정보를 담고 있는 커스텀 클래스를 만들어 준다.

컨트롤러에서 @ExceptionHandler를 사용하여 SampleException이 발생할 때 쓰는 error handler를 만들어준다.

그럼 /hello 요청을 하면 만들어준 error hanlder가 정상 작동함을 볼 수 있다.

@ExceptionHandler

@ExceptionHandler같은 경우는 @Controller, @RestController가 적용된 Bean내에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능을 한다.

@RestController 
public class MyRestController
{ ... ...
	@ExceptionHandler(NullPointerException.class)
	public Object nullex(Exception e) {
		System.err.println(e.getClass()); return "myService"; 
	}
}

위와 같이 적용하기만 하면 된다. @ExceptionHandler라는 어노테이션을 쓰고 인자로 캐치하고 싶은 예외클래스를 등록해주면 끝난다.

→ @ExceptionHandler({ Exception1.class, Exception2.class}) 이런식으로 두 개 이상 등록도 가능하다.

위의 예제에서 처럼하면 MyRestController에 해당하는 Bean에서 NullPointerException이 발생한다면, @ExceptionHandler(NullPointerException.class)가 적용된 메서드가 호출될 것이다.

주의사항/알아 둘 것

  • Controller, RestController에만 적용가능하다. (@Service같은 빈에서는 안됨.)
  • 리턴 타입은 자유롭게 해도 된다. (Controller내부에 있는 메서드들은 여러 타입의 response를 할 것이다. 해당 타입과 전혀다른 리턴 타입이어도 상관없다.)
  • @ExceptionHandler를 등록한 Controller에만 적용된다. 다른 Controller에서 NullPointerException이 발생하더라도 예외를 처리할 수 없다.
  • 메서드의 파라미터로 Exception을 받아왔는데 이것 또한 자유롭게 받아와도 된다.



@ControllerAdvice

@ExceptionHandler가 하나의 클래스에 대한 것이라면, @ControllerAdvice는 모든 @Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation이다.

@RestControllerAdvice 
public class MyAdvice {
	@ExceptionHandler(CustomException.class)
	public String custom() 
	{ 
    	return "hello custom"; 
    }
}

위와 같이 새로운 클래스파일을 만들어서 annotation을 붙이기만 하면 된다. 그 다음에 @ExceptionHandler로 처리하고 싶은 예외를 잡아 처리하면 된다.

별도의 속성값이 없이 사용하면 전역에 있는 컨트롤러를 담당하게 된다.

@RestControllerAdvice랑 @ControllerAdvice가 있는데 말 그대로 @RestControllerAdvice는 @RestController에서 발생한 Exception만 캐치하고, @ControllerAdvice는 @Controller에서 발생한 Exception만 캐치한다.

  @RestController
  public class MyRestController {

    @Autowired
    private MyService myService;

    @GetMapping("/serviceException")
    public String serviceException() {
      return myService
          .serviceExceptionMethod(); //service에서 CustomException 발생 }
      }
          //...
      @Controller
      public class HelloController { 
      @GetMapping("/jeongpro")
      public String jeongpro() {
      throw new CustomException(); 
      }
    }
 }

위와 같이 두개의 컨트롤러를 작성했을 때 @RestControllerAdvice를 사용하면 @Controller로 적용한 HelloController에서 발생하는 예외는 @RestControllerAdvice에서 잡아주지 못한다.

또한, 만약에 전역의 예외를 잡긴하되 패키지 단위로 제한할 수도있다.

@RestControllerAdvice("com.example.demo.login.controller")

login모듈에 있는 RestController에서 발생하는 예외를 잡으려면 위와 같이 하면 된다. (패키지 구성을 잘하면 유용하다)



참고 : https://jeong-pro.tistory.com/195 , https://velog.io/@max9106/Spring-Boot-ExceptionHandler

반응형
Comments