--- title: 'Sums up servlet lifecycle, with AOP perspective' disqus: hackmd --- Sums up servlet lifecycle, with AOP perspective === ![downloads](https://img.shields.io/github/downloads/atom/atom/total.svg) ![build](https://img.shields.io/appveyor/ci/:user/:repo.svg) ![chat](https://img.shields.io/discord/:serverId.svg) [TOC] ## Abstract The discussion would end up with two topics: - Request/Response lifecycle upon springboot-framework servlet - Disect the subtle differences between such AOP concepts in Java as Filter, Interceptor and AOP aspect. Before getting in into two topics mentioned above, we should introduce servlet for comprehensiveness in advance even though it's cliche. \ Then, given the servlet framework upon springboot, completed lifecycle of request would be splitted by the pivot into 2 parts in favor of increasing the fluency of flow we're going to discuss, the pivot called **servlet container**. \ The context would head forward to the conclusion following 3 steps below: 1. What task will be done on the server side after the Web Container(Tomcat) receives the request sent from web page, percisely called Client? 2. How do the request and response be "encapulated" and conveyyed around the inside and outside of the servlet container? 3. How to dispatch the request sent into servlet container to the coresponding servlet application? Besides, the configuration issue on handlerMapping or handlerAdapter however would not be addressed. The deployment of AOPs and the mechanism of them within the servlet application are the most intriguinig topics that I would like to share with you. Further, this guide would go through the whole lifecycle outside/inside the servlet by depicting a user story, Having Tattoo, in the meanwhile introducing such various AOP concepts often implemented in Java as Filter, Interceptor and AOP aspect, each of section attached with codes and the running results. ## What is servlet #### A Java component offering service tackling with HttpRequest/Response As an intermediate component, SERVLET is an application bridging web explorer or other clients sending message end and service from server end for conveying response and request. #### For interacting in dynamic(real time) with client Compared to the static web page scripted in Html, css and JavaScript, dynamic web page could interact with client in real time as the servlet comes into play. ## Web Container(Tomcat) handling the request #### Tomcat as web container must transfer HttpRequest into the correct servlet application The ultimate goal of the client sending request is getting a expected response, with a process in which the application server handles dozens of business logics. To attain the final destination, Tomcat would be required to instantiate and load the correct servlet, parametize the request encapsulated and response moduled, and finally deliver them into the target servlet. ```sequence Client->Tomcat: send HTTPRequest Note over Tomcat, Servlet: instantiate the servlet Note over Tomcat: encapsulate into ServletRequest Tomcat->Servlet: send ServletRequest Note over Servlet: hanlding business logic Servlet->Tomcat: send ServletResponse Note over Tomcat: transform into HttpResponse Tomcat->Client: send HTTPResponse ``` However, then a question raised is how do Web Container load the corresponding servlet? #### Reflecting the Url, with SpringBootServletInitializer There are two ways to find servlet and reflect the url, where the second way is what we concern (as springboot framwork is the scope of this topic): - (general in Java web) Reflect the servlet setting configured in web.xml. - (Springboot) Instantiate the Java class - SpringBootServletInitializer - before running time. It's cliche but important to metion that the feature of auto-configuration springboot has should be iterated. Because of the trait we mention many times, springbootServletInitializer has set up all the default configuration you need to deal with basic mapping, implementing the interface - WebApplicationInitializer - with overridden method, the method that keeps listening, technically called observing, the request since the server was on. ```java= public abstract class SpringBootServletInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { //register a listener with a default context(setting) } } ``` Thus, the listener would complete the task as same as that web.xml has done, receiving the request and find the corrsponding servlet. New servlet would be instantiate if it was the first time being called, otherwise the servlet container would return an existed serlet having been called beforehand. So far, we've known how and when Web container builds up a servlet. Nevertheless, the accompanied issue appears as long as the servlet is loaded : **How would the request be handled** in the servlet just loaded? ## DispatcherServlet comes into play After the servlet is built up, it needs a player to arrange the channel for various requesting type, which could be GET, POST, PUT or other else, a player named dispatcherServlet. DispatcherServlet is a servlet class in which doDispatch() method has already been implemented. doDispatch() mainly deals with the calling of interceptor and handler. In other words, find the target controller and put the request in. Here is the summary of what doDispatch() has done for dispatching: ```sequence DispatcherServlet->handlerMapping: handlerMapping->DispatcherServlet: return a executionChain DispatcherServlet-->Interceptor: Interceptor->Handler: Note over Handler: do business logic Handler->Interceptor: Note left of Interceptor: Interceptor: afterCompletion Interceptor-->DispatcherServlet: feedback response ``` 1. getting handler through handlerMappings 2. getting handlerAdapter 3. apply pre-handelr of interceptor in execChain, provided through step1. 4. apply handler 5. apply post-handler ```java= protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // -------------------------------------------step1 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // -------------------------------------------step2 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // -------------------------------------------step3 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // -------------------------------------------step4 : the breakpoint invoking the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); // -------------------------------------------step5 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException("Handler dispatch failed", err); } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } } ``` In short, the dispatcherServlet is responsible for reflecting correct handler(controller) by calling handler mapping, which is auto-configured as well. #### A pause from discussing Lifecycle So far, we've observed the lifecycle traversing in a basic perspective from Web container to the handler that the request targets. Before we stride to the next step, let's take a retrospect on keypoints just mentioned above : 1. Tomcat as a web Container is in charge of instantiating corresponding servlet. 2. After servlet was loaded, Tomcat parametizes the encapsulated ServletRequest/Response and sends them into servlet in which service() has been auto-configured. 3. Inheritting the service() method, DispatcherServlet hands over the request to the target handler by getting instance from handlermapping. Yet it's not the end, the essential framework we protrayed is all for another greater canvas. In terms of AOP concepts, request should have gone through 3 "cuts" that we haven't mentioned in the sequence we framed, the cuts that also play an important role on lifecycle of request. ## Where do AOP play in the request lifecycle With a whole picture understanding how Request would be dispatched, the last part would address what "aspect" would be gone through before the request attains the handler(controller), focusing on discussing discrepency between 3 kinds of AOP implementation: - Filter - Interceptor - AOP ```sequence Note over Container: transform into HttpRequest Container->Filter: Note over Filter: do filter Filter->DispatcherServlet: Note over DispatcherServlet: do handler mapping DispatcherServlet->Interceptor: Note over Interceptor: do preHandle Interceptor->handler: Note over handler: controller handling business Note over handler: AOP enhancement handler->Interceptor: Note over Interceptor: do postHandle Interceptor-->Container: response Note over Container: transform into HttpResponse ``` #### An story analogous to lifecycle Given a story that a customer plans to tattoo a butterfly pattern. With mandotory limitation, the customer must have the membership to qualify for the service. Beside, the store implements a check-out-first policy, charging the service fee before tattooing. Speaking to the discount, you can buy one get one free if the customer is a newcomer. Then now, we could get in the process of tattoo. Before getting it started, the store notices that the bonus that every custormer possesses is that the natural background comes with the insect tattoo. At last, all the customer has to do is waiting until the process finishes. ### Filter #### Chapter in the story The front-desk is going to validate the membership of the client... #### Characteristics - Focus on coarse-grained task : Authentication - logging and auditing - Decouple any functionality from spring framework. #### Register process 1. implement interface - Filter 2. register as a Bean annotated with @Configuration ```java= @Slf4j public class TattooFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("validate membership for having tattoo."); //filter request HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; //filter response HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; httpResponse.reset(); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); httpResponse.getWriter() .print(new ObjectMapper() .writeValueAsString("response went through filter")); httpResponse.getWriter().flush(); filterChain.doFilter(servletRequest, servletResponse); } } ``` ```java= @Configuration public class BeanRegisterConfig { @Bean public FilterRegistrationBean filterRegistration(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new TattooFilter()); registrationBean.setName("TattooFilter"); registrationBean.addUrlPatterns("/tattoo"); //intercept the defined url pattern registrationBean.setOrder(1); //ranks higher priorty as number gets smaller return registrationBean; } } ``` ### Interceptor #### Chapter in the story 1. Formulating the check-out-first poicy, the store has to check the payment. in advance before service. 2. Check if the customer qualifies for the favor - buy one get one free. #### Characteristic - Deal with fine-grained task : more detailed authentication. - Enable to handling cross-cutting concerns : logging, pre/post-handle . - Manipulating spring context and model. >reminder : Conceptually different from @exceptionHandler, which is more closed to AOP class. (refer to the Annotation @RestControllerAdvice.) #### Register process: 1. Implement interface - HandlerInterceptor 2. register a bean implementing interface - WebMvcConfigurer #### The deployment of multi-Interceptor ```sequence Note over DispatcherServlet: do handlerMapping DispatcherServlet->Interceptor1: executionChain Note over Interceptor1: do preHandle1 Interceptor1->Interceptor2: Note over Interceptor2: do preHandle2 Interceptor2->Handler: Handler->Interceptor2: Note over Interceptor2: do postHandle2 Interceptor2->Interceptor1: Note over Interceptor1: do postHandle1 Note right of DispatcherServlet: do afterCompletion1 Note right of DispatcherServlet: do afterCompletion2 Interceptor1->DispatcherServlet: ``` ```java= @Slf4j public class PaymentValidInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("preHandle1 : check out the payment"); // If returns false, deliver to errorhandling. return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle1 : checked"); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("Interceptor1 completed"); HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } } ``` ```java= @Slf4j public class DiscountInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("preHandle2 : buy one get one free?"); return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle2 : done with 2 identical design"); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("Interceptor2 completed"); HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } } ``` ```java= @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { String[] addPathPatterns = {"/**"}; String[] excludePathPatterns = {}; //get more outlying when the object is added earlier. registry.addInterceptor(new BackgroundInterceptor()) .addPathPatterns(addPathPatterns) .excludePathPatterns(excludePathPatterns); registry.addInterceptor(new PolishInterceptor()) .addPathPatterns(addPathPatterns) .excludePathPatterns(excludePathPatterns); } } ``` ### AOP --- #### Chapter in the story The butterfly tatoo comes with a free natural background as long as the type of pattern requested is insect. #### Characteristics - Decoupling. - Being enable to enhance certain type of business logic. - Logging and auditing. #### AOP stresses on enhancement on the business logic As the "aspect" performs in the tattoo example, the advice effects the certain type of function by weaving, cofining the methods in classes that are designed to be enhanced. The regular expression given for @Poincut clarifies the cut for which the specific set of functions should apply. ```sequence Anywhere->Advice: request Note over Advice: @Before Note over Advice, Target methods: weaved Note over Advice: @After Advice->Anywhere: response ``` @pointcut weaves the advice into the target sets of methods, which in this case are defined in **Insect**, shown below, class, by declaring a [regular expression](https://www.baeldung.com/spring-aop-pointcut-tutorial). ![](https://i.imgur.com/aLaXkRk.png =50%x) ![](https://i.imgur.com/wHPvs42.png =50%x) :::info Digression : Based on the [dynamic proxies](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-introduction-proxies), AOP is not valid for static method. ::: ```java= @Slf4j @Aspect @Component @Order(1) public class InsectBackgroundAspect { //declaring regular expression @Pointcut(value = "execution(* com..service.Insect.*(..))") public void tattooPointCut(){} @Before("tattooPointCut()") public void doBefore(){ log.info("Aspect before : coming with a natural background"); } @After("tattooPointCut()") public void doAfter(){ log.info("Aspect After : frame it up!"); } } ``` ### Comparsion of 3 Aop ![](https://i.imgur.com/z6zWD91.png) Highlightening the AOP section, screenshot above presents the result running whole lifecycle. The discrepency between filter and interceptor is more clear than that between interceptor and AOP advice. We can easily discern filter and interceptor by scaling the magnitude of tasks. However, we should measure the odds in terms of the design idea that designer would like to convey. Implementing interceptive concept in 3 different ways presents distinct intention of designing from engineer. Interceptor is often used to **INTERCEPT**; while on the other hand, AOP advice is aming for **ENHANCEMENT**. Therefore, hybridizing 3 types of aop concept would hazard the maintainability as the your colleauge have trouble comprehending the intention of design. For example, it could be weird if the task for painting background were placed to the position on which authentication should have been, vice versa. In conclusion, even though they could be alternatively utilized on most scenario might identical to each other, such indulgent design should have to be avoided. The most important task all engineers must break down is clarifying the intention of your design. ## Appendix and FAQ :::info **Find this document incomplete?** Leave a comment! ::: ###### tags: `springboot` `servlet` `AOP` `Interceptor` `Filter`