์ฌ๊ธฐ ๊ฐ๋จํ ์ฅ๋ฐ๊ตฌ๋ ์ดํ๋ฆฌ์ผ์ด์ ์ด ์์ต๋๋ค.
์ฅ๋ฐ๊ตฌ๋์ ์ํ์ ์ถ๊ฐ, ์ ๊ฑฐ, ์กฐํํ๋ ๋ฑ ์ธ ๊ฐ์ง์ ์ผ์ ํ ์ ์์ต๋๋ค.
๊ทธ๋๋ ์๋ฌด๋ ๋ด ์ฅ๋ฐ๊ตฌ๋์ ์ํ์ ๋ด์ ์๋ ์์ต๋๋ค!
๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ง ์์ ์ ์ฅ๋ฐ๊ตฌ๋์ ์ํ์ ๋ด์ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ํ์ ๋ด๊ธฐ ์ ์ ์ํ์ ๋ด์ผ๋ ค๋ ์ฌ์ฉ์์ ์ธ์ฆ ์์ ์ ๋จผ์ ์ํํด์ผํฉ๋๋ค.
์ธ์ฆ ์์ ์ ๋ค์๊ณผ ๊ฐ์ ์ ์ฐจ๋ก ์งํ๋ฉ๋๋ค.
- 'Authorization' ํค๋ ์ถ์ถ
- ์ถ์ถ๋ ์ ๋ณด๋ก ์ฐ๋ฆฌ์ ์ฅ๋ฐ๊ตฌ๋ ์ดํ๋ฆฌ์ผ์ด์ ์ ํ์์ธ์ง ํ์ธ
์ด ์์ ์ ์ํ ์ถ๊ฐ, ์ํ ์ ๊ฑฐ, ์ํ ์กฐํ API์ ๋ชจ๋ ์ถ๊ฐ๊ฐ ๋์ด์ผ ํฉ๋๋ค.
@RestController
public class CartController {
@PostMapping("/carts/products/{productId}")
public void add() {
// 'Authorization' ํค๋ ์ถ์ถ
// ์ถ์ถ๋ ์ ๋ณด๋ก ํ์์ธ์ง ํ์ธ
// ์ํ ์ถ๊ฐ
}
@DeleteMapping("/carts/products/{productId}")
public void remove() {
// 'Authorization' ํค๋ ์ถ์ถ
// ์ถ์ถ๋ ์ ๋ณด๋ก ํ์์ธ์ง ํ์ธ
// ์ํ ์ ๊ฑฐ
}
@GetMapping("/carts/products")
public List<ProductDto> get() {
// 'Authorization' ํค๋ ์ถ์ถ
// ์ถ์ถ๋ ์ ๋ณด๋ก ํ์์ธ์ง ํ์ธ
// ์ํ ์กฐํ
}
}
์ฃผ์์ผ๋ก ๊ฐ๋จํ๊ฒ ํํํ์ง๋ง, ์ด๋ฅผ ์ค์ ์ฝ๋๋ก ์์ฑํ๋ค๋ฉด ๊ฐ์ ์ฝ๋๊ฐ ๊ธธ๊ฒ ๋ฐ๋ณต๋์ด ์์ฃผ ๋ถํธํ ๊ฒ ๊ฐ์ต๋๋ค.
๋ API๊ฐ ์ถ๊ฐ๋๋ค๋ฉด ์ค๋ณต ์ฝ๋๋ ๋ ๋์ด๋ ๊ฒ์ ๋๋ค.
์ฌ๊ธฐ์ ์ค๋ณต ๋ก์ง์ ๋ฐ๋ก ๋ถ๋ฆฌํด์ ์ฒ๋ฆฌํ ์๋ ์์๊น์?
์ด๋ Interceptor๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Interceptor๋?
์ธํฐ์ ํฐ๋ ๋ค์ด์จ ์์ฒญ์ ์ฒ๋ฆฌํ๊ธฐ ์ ์ ๊ทธ ์์ฒญ์ ๊ฐ๋ก์ฑ์ ์ด๋ค ์ผ์ ์ํํ๋ ์ญํ ์ ํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์์ ๊ณตํต๋ ์ธ์ฆ ๋ก์ง์ ์ธํฐ์ ํฐ๋ฅผ ์ด์ฉํด ํด๊ฒฐํ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค!
์ธํฐ์ ํฐ๋ HandlerInterceptor ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ฑฐ๋ HandlerInterceptorAdapter ํด๋์ค๋ฅผ ํ์ฅํ์ฌ ์ฌ์ฉํฉ๋๋ค.
HandlerInterceptor์๋ ์๋์ ๊ฐ์ด ์ธ ๊ฐ์ง์ ๋ฉ์๋๊ฐ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ค์ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ ์ํ๋ ์์ ์ ํ๋๋ก ํ ์ ์์ต๋๋ค.
- preHandler() - ํธ๋ค๋ฌ๊ฐ ์คํ๋๊ธฐ ์ ์ ํธ์ถ๋๋ค.
- postHandler() - ํธ๋ค๋ฌ๊ฐ ์คํ๋ ํ์ ํธ์ถ๋๋ค.
- afterCompletion() - ์์ฒญ์ด ์๋ฃ๋๊ณ ๋ทฐ๊ฐ ์์ฑ๋ ํ์ ํธ์ถ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ ํฌ๋ preHandle() ๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์ปจํธ๋กค๋ฌ๊ฐ ์คํ๋๊ธฐ ์ ์ ์ธ์ฆ ์์ ์ ํ ์ ์์ต๋๋ค.
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 'Authorization' ํค๋ ์ถ์ถ
// ์ถ์ถ๋ ์ ๋ณด๋ก ํ์์ธ์ง ํ์ธ
return true;
}
}
์ปจํธ๋กค๋ฌ์ ์๋ ๊ณตํต ๋ก์ง์ ์ ๊ฑฐํ ์ ์๊ฒ ๋์ต๋๋ค!
์ฐ๋ฆฌ๊ฐ ๋ง๋ ์ธํฐ์ ํฐ๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํด์ WebMvcConfigurer์ ๊ตฌํํ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ @Configuration ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ค๋๋ค.
WebMvcConfigurer์ addInterceptors() ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ ํ์ฌ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ์ธํฐ์ ํฐ๋ฅผ ๋ฑ๋กํฉ๋๋ค.
WebMvcConfigurer์ ๋ํ ์์ธํ ๋ด์ฉ์ ์๋ตํ๊ฒ ์ต๋๋ค. (๊ณต์๋ฌธ์ ์ฐธ๊ณ )
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor())
.addPathPatterns("/carts/**");
}
}
addPathPatterns๋ฅผ ํตํด ์ธํฐ์ ํฐ๊ฐ ๋์ํ URI๋ฅผ ์ง์ ํด์ค ์ ์์ต๋๋ค.
์ธํฐ์ ํฐ๊ฐ ์ ๋๋ก ๋์ํ๋ ์ง ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
๋์ ์์๋ฅผ ํ์ธํ๊ธฐ ์ํด ์ปจํธ๋กค๋ฌ์ ์กฐํ API์, ์ธํฐ์ ํฐ์ preHandle(), postHandle(), afterCompletion() ๋ฉ์๋์ ์ถ๋ ฅ๋ฌธ์ ์ถ๊ฐํฉ๋๋ค.


๊ทธ๋ฆฌ๊ณ GET ์์ฒญ์ ๋ณด๋ด๋ณด๋ฉด ์๋์ ๊ฐ์ ์์๋ก ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค!
์ด์ ์ธํฐ์ ํฐ์ ๋์์์์ ์ฌ์ฉ๋ฒ์ ๋ํด์๋ ์์์ต๋๋ค.
ํ์ง๋ง ๊ทผ๋ณธ์ ์ธ ๊ถ๊ธ์ฆ์ด ๋จ์ต๋๋ค.
์ด๋ป๊ฒ ์ธํฐ์ ํฐ๊ฐ ์ปจํธ๋กค๋ฌ์ ์์ฒญ ์ํ ์ ๊ณผ ํ์ ๋์์ ํ ์ ์๋์ง, ๋ด๋ถ ๋์์ด ๊ถ๊ธํฉ๋๋ค.
Interceptor๋ ์ด๋ป๊ฒ ๋์ํ ๊น?
์ธํฐ์ ํฐ๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ์๊ธฐ ์ํด์๋ DispatcherServlet์ HandlerMapping์ ๋ํด์ ์ ํ์๊ฐ ์์ต๋๋ค.
๊ทธ๋์ DispatcherServlet ๋ด๋ถ ์ฝ๋๋ฅผ ์ด์ง ์ดํด๋ณด์์ต๋๋ค.
๋ค์์ DispatcherServlet ๋ด์ doDispatch() ๋ฉ์๋ ์ ๋๋ค. ๊ทธ ์ค์์ ๋๋ถ๋ถ ์๋ตํ๊ณ ์ค์ํ ๋ถ๋ถ๋ง ๊ฐ์ ธ์์ต๋๋ค.
// DispatcherServlet๋ด์ doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ์๋ต..
HandlerExecutionChain mappedHandler = null;
// ์๋ต..
try {
// ์๋ต..
try {
// ์๋ต..
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
// ์๋ต..
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ์๋ต..
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// ์๋ต..
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
// ์๋ต..
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
์์ฒญ์ด ๋ค์ด์ค๋ฉด DispatcherServlet์ HandlerMapping์๊ฒ ์์ฒญ์ ๋ง๋ ํธ๋ค๋ฌ๋ฅผ ์ฐพ๋๋ก ์๊ตฌํฉ๋๋ค.
mappedHandler = getHandler(processedRequest);
์ด ๋ถ๋ถ์ด HandlerMapping์ด ํธ๋ค๋ฌ๋ฅผ ์ฐพ๋ ๋ถ๋ถ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
getHandler() ๋ด๋ถ๋ก ๋ค์ด๊ฐ๋ณด๋ฉด, ์ค์ ๋ก ๋ฑ๋ก๋ HandlerMapping ๋น๋ค์ ๋๋ฉด์ ํ์ฌ ๋ค์ด์จ ์์ฒญ์ ์ฒ๋ฆฌํ ํธ๋ค๋ฌ๋ฅผ ์ฐพ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
HandlerExecutionChain handler = mapping.getHandler(request);
์์ ๋ถ๋ถ์์ ํธ๋ค๋ฌ๋ฅผ ์ฐพ๋ ์ผ์ ์ํํ ๊ฒ ๊ฐ์ผ๋ getHandler() ๋ฉ์๋ ๋ด๋ถ๋ก ํ ๋ฒ ๋ ๋ค์ด๊ฐ๋ด ๋๋ค.
๊ทธ๋ผ ์๋์ ๊ฐ์ ์ฝ๋๊ฐ ์์ต๋๋ค. ์ค์ํ ๋ถ๋ถ๋ง ์ดํด๋ด ์๋ค.
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// ์๋ต..
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// ์๋ต ..
return executionChain;
}
getHandlerExecutionChain()์ด ์ต์ข ์ ์ผ๋ก HandlerExecutionChain ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋๊ตฐ์.
์ฌ๊ธฐ์ HandlerExecutionChain ํด๋์ค๊ฐ ๋ฌด์์ธ์ง ์ ๊น ์์๋ด ์๋ค.
HandlerExecutionChain์ ํธ๋ค๋ฌ์, ํธ๋ค๋ฌ์ ์ ์ฉ๋ ์ธํฐ์ ํฐ๋ค์ ๊ฐ์ง๊ณ ์๋ ํด๋์ค์ ๋๋ค.
๊ทธ๋ผ ๋ค์ ๋์์์ ๋ง์ง๋ง์ผ๋ก getHandlerExecutionChain()์ ์ดํด๋ด ์๋ค...!
๋๋์ด ์ฐพ์์ต๋๋ค!
์ฐ๋ฆฌ๊ฐ ๋ฑ๋กํ ์ธํฐ์ ํฐ๊ฐ ์๋์ง ํ์ธํ๊ณ HandlerExecutionChain์ ์ธํฐ์ ํฐ๋ฅผ ์ถ๊ฐํ ํ, ๊ทธ HandlerExecutionChain์ ๋ฐํํฉ๋๋ค.
๊ทธ๋ผ ๋ค์ DispatcherServlet์ doDispatch() ๋ฉ์๋๋ก ๋์๊ฐ ๋ด ์๋ค.
// DispatcherServlet๋ด์ doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ์๋ต..
HandlerExecutionChain mappedHandler = null;
// ์๋ต..
try {
// ์๋ต..
try {
// ์๋ต..
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
// ์๋ต..
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ์๋ต..
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// ์๋ต..
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
// ์๋ต..
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
getHandler()๋ฅผ ํตํด ๋ฐ์ HandlerExecutionChain์ mappedHandler ๋ณ์์ ๋์ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ค์ ํธ๋ค๋ฌ ๋ก์ง์ ์ํํ HandlerAdapter๋ฅผ ๊ฐ์ ธ์ ha ๋ณ์์ ๋์ ํฉ๋๋ค. (getHandlerAdapter() ๋ฉ์๋)
์ดํ ๋๋์ด ์ธํฐ์ ํฐ์ preHandle() ๋ฉ์๋๋ฅผ ์คํํ ๊ฒ ๊ฐ์ ์ฝ๋๊ฐ ๋ณด์ ๋๋ค.
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
์ค์ ๋ก applyPreHandle() ๋ฉ์๋ ๋ด๋ถ์์ ์ฐ๋ฆฌ๊ฐ ์ ์ํ preHandle() ๋ฉ์๋๋ฅผ ์คํํฉ๋๋ค.
๊ทธ ํ์ HandlerAdapter๊ฐ ํธ๋ค๋ฌ ๋ก์ง์ ์ํํฉ๋๋ค.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
์ฌ๊ธฐ์ ๋งํ๊ณ ์ถ์ ๊ฒ์, ์ค์ ์ปจํธ๋กค๋ฌ์ ๋ก์ง์ด ์ํ๋๊ธฐ ์ ์ธํฐ์ ํฐ์ preHandle()์ ์ํํ๋ ์ฝ๋๊ฐ ์คํ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ปจํธ๋กค๋ฌ์ ๋ก์ง์ด ์ํ๋ ํ postHandle()์ ์ํํ๋ ์ฝ๋๊ฐ ์๋ ๊ฒ๋ ํ์ธํ ์ ์์ต๋๋ค.
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
๋ง์ง๋ง์ผ๋ก processDispatchResult() ๋ด๋ถ๋ฅผ ํ์ธํด๋ณด๋ฉด ์ธํฐ์ ํฐ์ afterCompletion() ๋ฉ์๋๋ฅผ ์ํํ๋ ๋ก์ง์ ๋ณผ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
๊ฒฐ๋ก ์ ์ธํฐ์ ํฐ๋ DispatcherServlet ๋ด๋ถ์์ ๋ค์๊ณผ ๊ฐ์ ์์๋ก ๋์ํฉ๋๋ค.
- ์์ฒญ์ด ๋ค์ด์ค๋ฉด DispatcherServlet์ HandlerMapping์๊ฒ ์์ฒญ์ ๋ง๋ ํธ๋ค๋ฌ๋ฅผ ์ฐพ๋๋ก ํ๋ค.
- ํธ๋ค๋ฌ๋ฅผ ์ฐพ๋ ๊ณผ์ ์์ ๋ฑ๋ก๋ ์ธํฐ์ ํฐ๊ฐ ์๋์ง ํ์ธํ ํ ์ธํฐ์ ํฐ๋ ๋ฑ๋กํ๋ค.
- ์ค์ ํธ๋ค๋ฌ(์ปจํธ๋กค๋ฌ) ๋ก์ง์ ์ฒ๋ฆฌํ HandlerAdapter๋ฅผ ๊ฐ์ ธ์จ๋ค.
- HandlerAdapter๊ฐ ํธ๋ค๋ฌ ์ฝ๋๋ฅผ ์คํํ๊ธฐ ์ preHandle() ๋ฉ์๋๋ฅผ ์คํํ๋ค.
- ํธ๋ค๋ฌ ์ฝ๋๋ฅผ ์คํํ๋ค.
- postHandle() ๋ฉ์๋๋ฅผ ์คํํ๋ค.
- ์ดํ์ afterCompletion() ๋ฉ์๋๋ฅผ ์คํํ๋ค.
์ฐธ๊ณ ์๋ฃ
https://www.baeldung.com/spring-mvc-handlerinterceptor
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring Boot] Graceful shutdown์ผ๋ก ์์ ํ๊ฒ ์ข ๋ฃํ๊ธฐ (0) | 2024.08.30 |
---|---|
[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํ ์ ๋ฆฌ (0) | 2023.07.13 |
Dao์ Repository์ ๋ํด์... (0) | 2023.05.29 |
Mockito.mock(), @Mock๊ณผ @MockBean์ ์ฐจ์ด์ (1) | 2023.04.23 |