๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
BackEnd๐ŸŒฑ/Java

Java์˜ ์˜ˆ์™ธ ์ƒ์„ฑ ๋น„์šฉ์€ ๋น„์‹ธ๋‹ค

by ์•ˆ์ฃผํ˜• 2023. 3. 10.

์„œ๋ก 

๋ณดํ†ต ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ, ์•„๋ž˜์™€ ๊ฐ™์€ ์žฅ์  ๋•Œ๋ฌธ์— ์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์™ธ ํด๋ž˜์Šค ์™ธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ Custom Exception ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜์—ฌ ์ž์ฃผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 

  • ์—๋Ÿฌ ์ฒ˜๋ฆฌ์˜ ์ผ๊ด€์„ฑ๊ณผ ๊ฐ€๋…์„ฑ ์œ ์ง€: ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์˜ˆ์˜ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๋ฏ€๋กœ, ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‹ค ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์—๋Ÿฌ์ฒ˜๋ฆฌ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋กœ๊น… ๋ฐ ๋””๋ฒ„๊น…์— ์šฉ์ด: ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜ˆ์™ธ ํด๋ž˜์Šค์— ๋””๋ฒ„๊น… ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋””๋ฒ„๊น…์„ ์šฉ์ดํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์˜ ์œ ์—ฐ์„ฑ: ์˜ˆ์™ธ ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋Ÿฌํ•œ ์žฅ์  ์™ธ์—๋„, ์ž๋ฐ”์—์„œ๋Š” Exception์˜ ์ฒ˜๋ฆฌ ๋น„์šฉ์ด ๋งค์šฐ ๋น„์‹ธ๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ฒŒ์‹œ๊ธ€์—์„œ๋Š” JVM์—์„œ Exception์ด ์ฒ˜๋ฆฌ๋˜๋Š” ์ˆœ์„œ์™€ Exception์˜ ์ƒ์„ฑ ๋น„์šฉ์ด ๋น„์‹ผ ์ด์œ , ๊ทธ๋ฆฌ๊ณ  ๋น„์šฉ์„ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ชฉ์ฐจ

  • JVM์˜ Exception ์ฒ˜๋ฆฌ ์ˆœ์„œ
  • Exception ๋น„์šฉ์ด ์ƒ๊ธฐ๋Š” ์›์ธ
  • ๋น„์šฉ์„ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•

 

JVM์˜ Exception ์ฒ˜๋ฆฌ ์ˆœ์„œ

๋จผ์ € JVM์—์„œ Exception์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ณผ์ •์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์˜ˆ์™ธ ๋ฐœ์ƒ: ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด JVM์€ ์˜ˆ์™ธ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ๋ฉ”์„œ๋“œ์˜ ํ˜ธ์ถœ ์Šคํƒ์„ ์ถ”์ ํ•œ๋‹ค.
  2. ์˜ˆ์™ธ ๊ฐ์ฒด ์ „ํŒŒ: JVM์€ ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ๋ฉ”์„œ๋“œ์—์„œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ์ฐพ๊ณ , ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœ ์Šคํƒ์˜ ์ƒ์œ„ ๋ฉ”์„œ๋“œ๋กœ ์ „ํŒŒ์‹œํ‚จ๋‹ค.
  3. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ: ์˜ˆ์™ธ ๊ฐ์ฒด๊ฐ€ ์ƒ์œ„ ๋ฉ”์„œ๋“œ๋กœ ์ „ํŒŒ๋˜๋ฉด, ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” catch ๋ธ”๋ก์„ ์ฐพ๊ณ , ์—†๋‹ค๋ฉด ์˜ˆ์™ธ๋Š” ๋‹ค์‹œ ์ƒ์œ„ ๋ฉ”์„œ๋“œ๋กœ ์ „ํŒŒ๋œ๋‹ค.
  4. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์‹คํŒจ: ์˜ˆ์™ธ ๊ฐ์ฒด๊ฐ€ ์ตœ์ƒ์œ„ ๋ฉ”์„œ๋“œ๊นŒ์ง€ ์ „ํŒŒ๋˜์–ด๋„, ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” catch๋ธ”๋ก์ด ์—†๋Š” ๊ฒฝ์šฐ JVM์€ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•œ ๊ฒƒ์œผ๋กœ ํŒ๋‹จํ•˜์—ฌ ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” Default Exception Handler๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  5. Default Exception Handler ์‹คํ–‰: Default Exception Handler๋Š” ์˜ˆ์™ธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•˜๊ณ , ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์˜ˆ์™ธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์Šค๋ƒ…์ƒท ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜์—ฌ ๋””๋ฒ„๊น…์„ ์œ„ํ•œ ์ •๋ณด๋กœ ์ œ๊ณตํ•œ๋‹ค.

์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๋ฉ”์„œ๋“œ์—์„œ ๋ฐ”๋กœ ์ฒ˜๋ฆฌ๊ฐ€ ๋œ๋‹ค๋ฉด ๊ฐ€์žฅ ์ข‹์ง€๋งŒ, ๋ฐ”๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ๋ชปํ•˜๋ฉด JVM์€ ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ์„ ๋•Œ ๊นŒ์ง€ ๊ณ„์†ํ•ด์„œ ์ƒ์œ„ ๋ฉ”์„œ๋“œ๋กœ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋ฉ”๋ชจ๋ฆฌ์˜ ํ˜ธ์ถœ ์Šคํƒ(call stack)์„ ํƒ์ƒ‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
 

๋น„์šฉ์ด ์ƒ๊ธฐ๋Š” ์›์ธ

๋จผ์ € ํ˜ธ์ถœ ์Šคํƒ์„ ํƒ์ƒ‰ํ•˜๋Š” ๊ณผ์ • ์ž์ฒด๋„ ๋น„์šฉ์ด์ง€๋งŒ, fillInStackTrace() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์„ ์ˆœํšŒํ•˜๋ฉฐ ํด๋ž˜์Šค๋ช…, ๋ฉ”์„œ๋“œ๋ช…, ์ฝ”๋“œ ์ค„ ๋ฒˆํ˜ธ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๋ชจ์•„ stacktrace๋กœ ๋งŒ๋“œ๋Š” ๊ณผ์ • ๋˜ํ•œ ๋น„์šฉ ์ฆ๊ฐ€์˜ ์›์ธ์ž…๋‹ˆ๋‹ค.

fillInStackTrace()์— ์˜ํ•ด ๋ชจ์•„์ง„ ์ •๋ณด๋“ค

fillInStackTrace()๋Š” Throwable ํด๋ž˜์Šค์— ์ •์˜๋œ ๊ตฌํ˜„ ๋ฉ”์„œ๋“œ๋กœ ์ƒ์„ฑ์ž์—์„œ ํ˜ธ์ถœ๋˜๋„๋ก ๋˜์–ด์žˆ๋ฉฐ, ๋ชจ๋“  Exception์€ Throwable์„ ์ƒ์†๋ฐ›๋„๋ก ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— fillInStackTrace() ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ StackTrace๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์‹œ๊ฐ„์€ ๋ช‡ ๋ฐ€๋ฆฌ์ดˆ์—์„œ ๋ช‡ ์ดˆ๊นŒ์ง€ ๋‹ค์–‘ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ํ™˜๊ฒฝ, StackTrace์˜ ๊นŠ์ด, StackFrame์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ˆ˜, JVM์˜ ๋ฒ„์ „ ๋ฐ ์„ค์ • ๋“ฑ์— ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„์„ ์ •์˜ํ•˜๊ธฐ๋Š” ์–ด๋ ต์Šต๋‹ˆ๋‹ค. 

ํ•˜์ง€๋งŒ ์œ„์˜ ๋ช‡๋ช‡ ๋ธ”๋กœ๊ทธ๋ฅผ ๋ณด๋ฉด, Stack Trace๊ฐ€ ๊นŠ์„์ˆ˜๋ก ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค๋Š” ๊ฒƒ์€ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.
 

๋น„์šฉ์„ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•

  1. fillInStackTrace() ๋ฉ”์„œ๋“œ ์žฌ์ •์˜
  2. ์˜ˆ์™ธ ์บ์‹ฑ

1. fillInStackStrace ์žฌ์ •์˜

๋ณดํ†ต NullPointException์ด๋‚˜ OutOfMemory์™€ ๊ฐ™์ด ์ž๋ฐ”์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ œ์™ธํ•œ, ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  Custom Exception์€ ์—๋Ÿฌ์˜ ์ถ”์  ๋ณด๋‹ค๋Š” ์œ ํšจํ•˜์ง€ ์•Š๋Š” ๊ฐ’์ผ ๋•Œ ํ•˜์œ„ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ ์ฃผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณดํ†ตStackTrace๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 

@Override 
public synchronized Throwable fillInStackTrace() {
   return this;
}

๋•Œ๋ฌธ์— ๋‹จ์ˆœํžˆ Try-Catch๋กœ ์ดํ›„์˜ Flow๋ฅผ ์ œ์–ดํ•˜๊ฑฐ๋‚˜, Spring ํ™˜๊ฒฝ์—์„œ @ControllerAdvice๋กœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋ถˆํ•„์š”ํ•œ ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ์•„๋ฌด trace๋„ ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์ง์ ‘ ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ fillInStackTrace()๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ

์˜ˆ์‹œ ์ฝ”๋“œ

public class DuplicateLoginException extends RuntimeException {
    public DuplicateLoginException(String message) {
        super(message);
    }

    @Override
    public synchronized Throwable fillInStackTrace() {
        return this;
    }
}

 

fillInStackTrace() ์žฌ์ •์˜ ์ „ ์—๋Ÿฌ ์˜ˆ์‹œ

kancho.realestate.comparingprices.exception.DuplicateLoginException: ์ด๋ฏธ ๋กœ๊ทธ์ธํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
    at kancho.realestate.comparingprices.controller.UserController.validateDuplicateLogin(UserController.java:67)
    at kancho.realestate.comparingprices.controller.UserController.login(UserController.java:44)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
    at 

... ์ƒ๋žต

 

fillInStackTrace() ์žฌ์ •์˜ ํ›„ ์—๋Ÿฌ ์˜ˆ์‹œ

kancho.realestate.comparingprices.exception.DuplicateLoginException: ์ด๋ฏธ ๋กœ๊ทธ์ธํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

2. ์˜ˆ์™ธ ์บ์‹ฑํ•˜๊ธฐ

static final๋กœ ์„ ์–ธํ•˜์—ฌ ์ด์šฉํ•ด ์˜ˆ์™ธ๋ฅผ ๋ฏธ๋ฆฌ ์บ์‹ฑํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ์ข…์˜ ์ƒ์ˆ˜ ๊ฐ’ ํ˜•ํƒœ๋กœ ์˜ˆ์™ธ๋ฅผ ์บ์‹ฑํ•ด ๋‘๊ณ  ์“ฐ๋Š” ๊ฒƒ์ด ๋งค๋ฒˆ ๊ฐ™์€ ์ข…๋ฅ˜์˜ ์˜ˆ์™ธ๋กœ new๋กœ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋ณด๋‹ค ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

public class CustomException extends RuntimeException {
    public static final CustomException INVALID_NICKNAME = new CustomException(ResponseType.INVALID_NICKNAME);
    public static final CustomException INVALID_PARAMETER = new CustomException(ResponseType.INVALID_PARAMETER);
    public static final CustomException INVALID_TOKEN = new CustomException(ResponseType.INVALID_TOKEN);
    //์ƒ๋žต
}

์œ„์™€ ๊ฐ™์ด Exception ํด๋ž˜์Šค์— ์˜ˆ์™ธ ์ƒํ™ฉ์— ๋Œ€ํ•œ ์ ๋‹นํ•œ ์‘๋‹ต ๋ฉ”์‹œ์ง€๋‚˜ ์ฝ”๋“œ๋ฅผ ๋‹ด๋„๋ก ํ•œ ๋’ค, ์•„๋ž˜์ฒ˜๋Ÿผ ์˜ˆ์™ธ ๋ฐœ์ƒ ์ƒํ™ฉ์—์„œ new ํ‚ค์›Œ๋“œ ์—†์ด throw๋ฅผ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

if (StringUtils.isBlank(parameter)) {
	throw WebtoonCoreException.INVALID_PARAMETER;
}

 
 

์ฐธ๊ณ 

๋Œ“๊ธ€