๐ง ์๋ก
์คํ๋ง์์๋ ์ธํฐ์ ํฐ๋ฅผ ํตํด, ์ปจํธ๋กค๋ฌ(ํธ๋ค๋ฌ)๋ฅผ ํธ์ถํ๊ธฐ ์ ๊ณผ ํ์ ์ถ๊ฐ์ ์ธ ์์ ๋ค์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํด์ค๋๋ค.
์๋ฅผ ๋ค์ด ์ธ์ฆ ์ ๋ณด๋ฅผ ํ์ธํ๋ ๋ฑ์ ์์ ์ด ์์ ์ ์๊ฒ ๋ค์.
์ธํฐ์ ํฐ์ ๋ํด์๋ ๋ค์ ๊ธ์ ์ฐธ๊ณ ํด์ฃผ์ธ์.
์ด๋ฒ ๊ธ์์๋ ์ธํฐ์ ํฐ๊ฐ ์ค์ ๋ก ์ด๋ค ์์ผ๋ก ๋์ํ๋์ง ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฐ์ ์ค๋ช ์ ํธ์๋ฅผ ์ํด HandlerExecutionChain๋ถํฐ ์ดํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๐ง HandlerExecutionChain
HandlerExecutionChain์ ์์ ๊ฐ์ด ํธ๋ค๋ฌ์, ํด๋น ํธ๋ค๋ฌ์ ์ ์ฉ๋ ์ธํฐ์ ํฐ๋ค์ ๊ฐ์ง๊ณ ์๋ ํด๋์ค์ ๋๋ค.
(@Controller์ @RequestMapping์ผ๋ก ์ ์ํ ๋ฉ์๋๊ฐ ํ๋์ ํธ๋ค๋ฌ๊ฐ ๋ ์ ์์ต๋๋ค.)
์ฆ HandlerExecutionChain์ ํตํด, ์ธํฐ์ ํฐ๋ฅผ ์ ์ฉํ๊ณ ํธ๋ค๋ฌ ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.
๐ง DispacherServlet
์ฐ์ ์ธํฐ์ ํฐ์ ๋๋ต์ ์ธ ์๋ ๊ณผ์ ์ ํ์ธํ๊ธฐ ์ํด DispacherServlet ๋ถํฐ ์ดํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฐ์ http ์์ฒญ์ด ๋ค์ด์จ๋ค๋ฉด, ํด๋น ์์ฒญ์ ๋์๋๋ ํธ๋ค๋ฌ(์ปจํธ๋กค๋ฌ)๋ฅผ ์ฐพ๋ ๊ณผ์ ์ ๊ฑฐ์นฉ๋๋ค.
๋ง์ฝ ํด๋น ์์ฒญ์ ์ฒ๋ฆฌํ ํธ๋ค๋ฌ๊ฐ ์๋ค๋ฉด noHandlerFound()๊ฐ ํธ์ถ๋ ํ ๊ทธ๋๋ก ๋ฆฌํด๋๋ฏ๋ก ์ธํฐ์ ํฐ๊ฐ ํธ์ถ๋์ง ์์ต๋๋ค.
์ด? ์๋๋ฐ์? ํธ์ถ๋๋๋ฐ์?'
> ํด๋น ์ธํฐ์ ํฐ๊ฐ /error์ ๋งคํ๋๊ฑฐ๋,
ํน์ ResourceHttpRequestHandler ๋๋ฌธ์ผ ๊ฒ์ ๋๋ค.
/error ๋๋ฌธ์ด๋ผ๋ฉด excludePathPatterns์ /error๋ฅผ ์ถ๊ฐํ๊ฑฐ๋,
spring.mvc.throw-exception-if-no-handler-found=true ๋ฅผ ํตํด ํด๊ฒฐํ ์ ์์ผ๋ฉฐ,
ResourceHttpRequestHandler์ ๋ํ ๋ด์ฉ์ ์คํ๋ง ์ธํฐ์ ํฐ ์ ์ฉ ์ NOT FOUND๊ฐ ๋ฐ์ํ์ง ์๋ ๊ฒฝ์ฐ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์)
getHandler()์์ ๋ฐํ๋๋ ํธ๋ค๋ฌ๋ HandlerExecutionChain์ผ๋ก, ์์์ ์ดํด๋ณด์๋ฏ ์ธํฐ์ ํฐ๊ฐ ํฌํจ๋ ํธ๋ค๋ฌ์ ๋๋ค.
์ดํ mappedHandler.applyPreHandle()์ด ์คํ๋๋๋ฐ์, ์ด๊ณณ์์ ์ธํฐ์ ํฐ์ preHandle()์ด ์ํ๋ฉ๋๋ค.
์ดํ ํธ๋ค๋ฌ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ค applyPostHandler()์ ํตํด ์ธํฐ์ ํฐ์ afterHandler()์ด ํธ์ถ๋ฉ๋๋ค.
์ด์ด์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์์์ ์ดํด๋ณธ ๊ณผ์ ๋ค์ ์งํํ๋ฉฐ ์์ธ๊ฐ ๋ฐ์ํ๊ฑฐ๋, ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋๊ฑฐ๋์ ์๊ด์์ด, ๋ง์ง๋ง์ผ๋ก๋ processDispatchResult()๊ฐ ์คํ๋๊ฒ ๋ฉ๋๋ค.
์๋์์ ์ดํด๋ณด๊ฒ ์ง๋ง, processDispatchResult() ๋ด๋ถ์์ ์ธํฐ์ ํฐ์ afterCompletion()์ด ํธ์ถ๋ฉ๋๋ค.
๋ง์ฝ processDispatchResult()์์ ์์ธ๊ฐ ๋ฐ์ํ๋ค๋ฉด catch๋ฌธ์ ๊ฑธ๋ฆฐ ๋ค์ triggerAfterCompletion()๋ฉ์๋๊ฐ ํธ์ถ๋๋๋ฐ,
์ด๊ณณ์์ ์ธํฐ์ ํฐ์ afterCompletion()๊ฐ ํธ์ถ๋๊ฒ ๋ฉ๋๋ค.
์ฆ afterCompletion()์ ์ด๋ ํ ์ํฉ์์๋ ํธ์ถ๋๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์๋ฌธ์ด ํ๋ ์๊น๋๋ค.
์ธํฐ์ ํฐ์ afterCompletion()์ ์์ฒญ์ ์ฒ๋ฆฌํ ํธ๋ค๋ฌ๊ฐ ์์ด๋ ์คํ๋๋์?
> ์๋๋๋ค.
processDispatchResult()์ triggerAfterCompletion()์ ๋ณด๋ฉด ํธ๋ค๋ฌ๊ฐ ์๋ ๊ฒฝ์ฐ์๋ง ์ธํฐ์ ํฐ์ afterCompletion()์ด ํธ์ถ๋๋๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
๊ฐ๋จํ triggerAfterCompletion()๋ถํฐ ์ดํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
processDispatchResult()๋ ์๋์ ๊ฐ์ด ๊ตฌํ๋์ด ์์ต๋๋ค.
processDispatchResult()์์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด triggerAfterCompletion()์ด ํธ์ถ๋๋ ๊ฒ์ ์์์ ์ดํด๋ณด์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ processDispatchResult() ๋ด๋ถ์์๋ afterCompletion()์ ํธ์ถํ๋ฉฐ, triggerAfterCompletion() ๋ด๋ถ์์๋ afterCompletion() ๋ฅผ ํธ์ถํฉ๋๋ค.
์ฆ ์ด๋ก์ธํด processDispatchResult() ๋ด๋ถ์์ ํธ์ถ๋ ์ธํฐ์ ํฐ์ afterCompletion()์์ ์์ธ๊ฐ ๋ฐ์ํ๋ค๋ฉด,
triggerAfterCompletion()์์ ์ธํฐ์ ํฐ๊ฐ ํ๋ฒ ๋ ํธ์ถ๋ ๊น์?
์ด๋ ์๋๋๋ค.
์ด๋ฌํ ์ด์ ๋ HandlerExecutionChain์ triggerAfterCompletion() ๋ฉ์๋์ ์๋๋ฐ์, ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์์ต๋๋ค.
์ง๊ธ๊น์ง ์ดํด๋ณธ ๋ด์ฉ๋ค์ ๋ฐํ์ผ๋ก ์ ์ ์๋ ๊ฒ์ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๋ ํธ๋ค๋ฌ(์ปจํธ๋กค๋ฌ)๊ฐ ์๋ค๋ฉด ์ธํฐ์ ํฐ๋ ์๋ํ์ง ์์ต๋๋ค.
์ธํฐ์ ํฐ์ preHandle, postHandle์์ ์์ธ๊ฐ ๋ฐ์ํ๋ค๋ฉด, @ControllerAdvice์์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์ธํฐ์ ํฐ์ afterCompletion์์ ์์ธ๊ฐ ๋ฐ์ํ๋ค๋ฉด, @ControllerAdvice๋ฑ์์ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ, ๋จ์ํ ๋ก๊ทธ๋ง ์ฐํ๋๋ค.
์ง๊ธ๊น์ง ์ธํฐ์ ํฐ์ preHandle, postHandle, afterCompletion์ ๋์ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์๋๋ฐ์,
์ด์ ๋ถํฐ๋ ์ด๋ป๊ฒ ์ฐ๋ฆฌ๊ฐ ๋ฑ๋กํ ์ธํฐ์ ํฐ๊ฐ ํธ๋ค๋ฌ์ ์ ์ฉ๋๋์ง๋ฅผ ์ดํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
ํธ๋ค๋ฌ์ ์ธํฐ์ ํฐ๋ฅผ ์ ์ฉํ๊ธฐ ์ํด์ HandlerExecutionChain์ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๋งจ ์์์ ์ดํด๋ณด์๋๋ฐ์,
HandlerExecutionChain์ ๋ง๋๋ ๊ณผ์ ์์ ์ด๋ ํ ๋ฐฉ์์ผ๋ก ์ ์ฉํ ์ธํฐ์ ํฐ๋ค์ด ์ค์ ๋๋์ง ํ์ธํ๋๋ก ํ๊ฒ ์ต๋๋ค.
HandlerExecutionChain๋ฅผ ์์ฑํ๋ DispatcherServlet์ getHandler() ๋ฉ์๋๋ฅผ ์ดํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๐ง getHandler๋ฅผ ํตํด HandlerExecutionChain๋ฅผ ๋ง๋๋ ๊ณผ์
์ฐ์ ์์ ๊ฐ์ด DispatcherServlet์ด ๊ฐ์ง handlerMappings๋ฅผ ์ํํ๋ฉฐ,
์์ฒญ(request)์ ๋์๋๋ ํธ๋ค๋ฌ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ณผ์ ์ ์ํํฉ๋๋ค.
์ปจํธ๋กค๋ฌ๋ฅผ @Controller์ @RequestMapping์ ์ฌ์ฉํ์ฌ ๊ตฌํํ์๋ค๋ฉด
์ฌ๋ฌ handlerMappings ์ค RequestMappingHandlerMapping์์ ์ฐพ์ ์ ์์ต๋๋ค.
RequestMappingHandlerMapping์ AbstractHandlerMapping์ ์์๋ฐ์ ๊ตฌํ๋์ด์์ผ๋ฉฐ,
AbstractHandlerMapping์ getHandler()๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์์ฒ๋ผ, ๋ด๋ถ์์ getHandlerExecutionChain() ๋ฉ์๋๋ฅผ ํตํด HandlerExecutionChain์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
getHandlerExecutionChain ๋ด๋ถ์์ ์ ํฌ๊ฐ ๋ฑ๋กํ ์ธํฐ์ ํฐ๋ค์ด ๋ฑ๋ก๋๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
์ธํฐ์ ํฐ๋ฅผ ๋ฑ๋กํ๋ ๊ณผ์ ์์ MappedInterceptor์ ๊ฒฝ์ฐ์๋ matches()์ ๊ฒฐ๊ณผ๊ฐ true์ธ ๊ฒฝ์ฐ์๋ง ๋ฑ๋ก๋๋๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
MappedInterceptor๋ ๋ฌด์์ผ๊น์?
์ด์ ๋ํด์ ์์๋ณด๊ธฐ ์ ์, ์ฐ์ ์์์ DispatcherServlet์ ๋ฑ๋ก๋ adaptedInterceptors๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
includePatterns ํน์ excludePatterns๊ฐ ์๋ ์ธํฐ์ ํฐ๋ MappedInterceptor๊ฐ ๋๋ฉฐ,
๊ทธ๋ ์ง ์์ ์ธํฐ์ ํฐ๋ ๊ทธ๋ฅ ๋ฑ๋ก๋๋ ๊ฒ์ ์์ํ ์ ์์ต๋๋ค.
(NoPathInterceptor๋ ์ ๊ฐ ์ง์ด์ค ์ธํฐ์ ํฐ ํด๋์ค๋ช ์ ๋๋ค)
๐ง MappedInterceptor
MappedInterceptor๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์์ต๋๋ค.
์ธํฐ์ ํฐ๋ฅผ ๋ฑ๋กํ๋ ๊ฒฝ์ฐ์๋ ์ธํฐ์ ํฐ์ ๋ํด์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ์ฌ ๋ฑ๋กํ๊ฑฐ๋, ํน์ ์ง์ ํ์ง ์๊ณ ๋ฑ๋กํ ์ ์์ต๋๋ค.
@Component
public class Config implements WebMvcConfigurer {
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new SetPathInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/error"); // ๊ฒฝ๋ก ์ง์ -> MappedInterceptor
registry.addInterceptor(new NoPathInterceptor())
.order(2); // ๊ฒฝ๋ก ์ง์ X -> ๋ฑ๋กํ ์ธํฐ์
ํฐ ๊ทธ๋๋ก ๋ฐํ
}
}
์ด๋ ์ ์์ ๊ฒฝ์ฐ MappedInterceptor๋ก ํฌ์ฅ๋์ด ์์ฑ๋๋๋ฐ, ์์ฑ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
mappedInterceptor์ matches()๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์์ต๋๋ค.
์ด๋ฅผ ํตํด interceptor์ excludePath์ includePath๊ฐ ๋์ผํ๊ฒ ๋ฑ๋ก๋๋ค๋ฉด excludePath๊ฐ ๋จผ์ ๋์ํ๋ ๊ฒ๋ ์ ์ ์์ต๋๋ค.