수 많은 우문은 현답을 만든다

예외처리에 대한 고찰 - 1편 본문

개발지식/Springboot

예외처리에 대한 고찰 - 1편

aiden.jo 2022. 2. 21. 18:44

예외처리에 대한 고찰

 

안녕하세요 조영호입니다.

오늘은 어플리케이션의 예외처리에 대해 고민하고 발견한 내용들에 대해서 공유하고자 합니다.

막연한 시작에서 한 걸음 나아간 결과를 얻게되어 뿌듯합니다.. 부족한 점은 댓글 달아주세요!


어느날 새로운 프로젝트 팀으로 이동하게 되었습니다. 첫 미션은 해당 어플리케이션의 에러들을 '잘 관리할 수 있게 해봐라' 였습니다.

에러 모니터링이야 그냥 ELK/EFK 쓰면 간단할 것으로 생각했지만, 어플리케이션 단에서 저장해서 보여주고 싶다는 요건이었습니다.

(찾다보니 front-end browser log를 저장하는 솔루션도 있더라구요 ! - Sentry)

 

해당 애플리케이션은 이미 메소드 별로 try-catch를 덕지덕지 쓴 상태였습니다. 어떻게하면 가독성을 향상시킬 수 있을까 고민하던 중 제가 읽었던 책인 클린코드를 생각하며 exceptionHandler를 떠올렸습니다. (기특 + 1점)

 

우리는 controller 별로 exceptionHandler를 선언해서, 컨트롤러 하위 로직들에서 발생하는 에러들을 공통으로 처리할 수 있습니다.

그런데 이 컨트롤러에서는 exceptionHandler이 작동하겠지만, 다른 컨트롤러에서도 동작을 할까요?

정답은 아닙니다. 각 컨트롤러마다 exceptionHandler를 만들어줘야 하는데 이 애플리케이션은 컨트롤러만 100개가 넘었습니다. OMG

 


구글링을 하던 중 발견한 controllerAdvice를 쓰면 한번 더 멋진 코드를 짤 수 있다는 것을 알게되었습니다.

 

@ControllerAdvice 어노테이션이 선언된 클래스에 @ExceptionHandler 을 쓰면 컨트롤러 전역으로 예외처리를 할 수 있습니다.

ControllerAdvice의 기본 동작 이해를 위해 링크를 남겨드립니다.

 

막상 코드를 짜놓고 나니 몇 가지 질문 때문에 머리가 혼란스러웠습니다.

try-catch < ExceptionHandler < ControllerAdvice 순으로 공통처리가 가능한 예외처리 방식으로 생각이 되는데요, 그럼 다 같이 존재하는 코드에서는 어떤것이 우선순위로 동작할까요? 혹은 전부 다 동작할까요?

 

Q1. 컨트롤러에 있는 exceptionHandler와 controllerAdvice의 exceptionHandler 중 누가 먼저 동작할까?
정답은 컨트롤러의 exceptionHandler가 우선순위를 가져가서 controllerAdvice는 동작하지 않는다입니다.

그럼  컨트롤러의 exceptionHandler를 없애줘야겠네요. 또는 컨트롤러에서 부분처리를 하고 예상하지 못한 부분을 controllerAdvice에서 처리하도록 하면 됩니다. (실험)

 

Q2. controllerAdvice에서 예외 공통처리는 했는데 메소드별로 남아있는 try-catch는 삭제해야될까?

정답은 다 삭제하면 안된다 입니다.

재시도를 통해 '예외복구'를 하는 경우도 있기 때문입니다. 예를 하나 들어보겠습니다.

while(retry-- > 0){
	try{
    //예외가 발생할 수 있는 범위
    	return; //성공시 리턴
    }catch (Exception e){
    	//네트워크 지연에 의한 대기
    }finally{
    	//리소스 반납
    }
}
throw new RetryFailedException(); //재시도 횟수 초과로 직접 예외 발생

 

위 코드는 네트워크 지연이 발생했을때 예외 블록에서 잡고있다가 제한 횟수안에 통신이 되면 성공 결과를 반환할 수 있습니다. try-catch 블록이 없어서 바로 예외 처리를 해버렸다면 사용자는 바로 접속 장애를 맞이했을 것 입니다. (참고)

 

반면 무분별한 try-catch는 줄이면 좋습니다. 예를들어서 catch만 선언해놓고 블록 안에서 예외처리를 안한다면 예외는 없겠지만 나중에 예외가 발생했을때 원인을 확인하기 어렵습니다. 한 가지 참고할 점은, try-catch 에서 예외를 처리해버리면 controllerAdvice 까지 예외가 도착하지 않습니다. 결과적으로 글로벌 익셉션 처리를 위해서는 try-catch를 줄여도 되지만 섣불리 다 삭제하면 안됩니다. (실험)

 

 

감사합니다.