The beauty of design patterns-behavior-template patterns (27)

What is template mode

The template method pattern defines an algorithm skeleton in a method and defers certain steps to subclasses. The template method pattern allows subclasses to redefine certain steps in the algorithm without changing the overall structure of the algorithm.

The role of template mode

Reuse and expansion

Standard implementation

public  abstract  class AbstractClass {
     public  final  void templateMethod () { 
        .... handles some initialization operations or common logic 
        // ... 
        method1 ();
         // ... 
        method2 ();
         // ... 
    }
     // define Good template method 1 
    protected  abstract  void method1 ();
     // Defined template method 2 
    protected  abstract  void method2 (); 
} 

// Implementation 1 
public  class ConcreteClass1 extends AbstractClass {
     //The parent class initializes its own processing logic 
    @Override
     protected  void method1 () {
         // ... 
    } 

    @Override 
    protected  void method2 () {
         // ... 
    } 
} 
// Implement 2 
public  class ConcreteClass2 extends AbstractClass {
     // The parent class initializes its own processing logic 
    @Override
     protected  void method1 () {
         // ... 
    } 

    @Override 
    protected  void method2 () {
         // ... 
    } 
}

AbstractClass demo = ConcreteClass1();
demo.templateMethod();

 

Use in source code

DispatcherServlet

org.springframework.web.servlet.FrameworkServlet do some initialization operations

protected  final  void processRequest (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         long startTime = System.currentTimeMillis (); 
        Throwable failureCause = null ;
         / ** 
         * <31> Get the current thread internationalization context from inside 2 ThreadLocal Get 
         * org.springframework.web.filter.RequestContextFilter # initContextHolders 
         * If this filter is configured here every request has been initialized spring boot Verification 
         * / 
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext ();
         // Build the current thread when this request is international Contextualization
        LocaleContext localeContext = this .buildLocaleContext (request);
         / ** 
         * <32> Get the RequestAttribute of the current thread request which will be obtained from 2 ThreadLocal 
         * org.springframework.web.filter.RequestContextFilter # initContextHolders has initialized spring boot verification 
         * / 
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes ();
         // <4> If the thread cache has not been built, it means that 
        ServletRequestAttributes have not been initialized before requestAttributes = this .buildRequestAttributes (request, response, previousAttributes);
         / **  
         * will be obtained from requsetAttribute To initialize one and then set it in key = WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE
         * means that we can follow after reqeust.getAttribute (WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE) Get 
         * Used to manage asynchronous requests
         * / 
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager (request); 
        asyncManager.registerCallableInterceptor (FrameworkServlet. Class .getName (), new FrameworkServlet.RequestBindingInterceptor ());
         / ** 
         * <5> This will be stored according to the current object idiom variable To which thread cache threadContextInheritable defaults to false 
         * We can use the previous BeanWapper to modify 
         * Indicates that we can get it later based on LocaleContextHolder and RequestContextHolder 
         * 
         * / 
        this .initContextHolders (request, localeContext, requestAttributes); 

        try {
             // <6> Abstract methods are implemented by subclasses such as: DispatcherServlet implements 
            this.doService(request, response);
        } catch (ServletException var17) {
            failureCause = var17;
            throw var17;
        } catch (IOException var18) {
            failureCause = var18;
            throw var18;
        } catch (Throwable var19) {
            failureCause = var19;
            throw new NestedServletException("Request processing failed", var19);
        } finally {
             / ** 
             * <7> The default previousLocaleContext previousAttributes is null 
             * This is mainly to clear the previousLocaleContext previousAttributes cached by the thread 
             * / 
            this .resetContextHolders (request, previousLocaleContext, previousAttributes);
             if (requestAttributes! = null ) { 
                requestAttributes. requestCompleted (); 
            } 

            if ( this .logger.isDebugEnabled ()) {
                 if (failureCause! = null ) {
                     this .logger.debug ("Could not complete request" , (Throwable) failureCause); 
                } else  if(asyncManager.isConcurrentHandlingStarted ()) {
                     this .logger.debug ("Leaving response open for concurrent processing" ); 
                } else {
                     this .logger.debug ("Successfully completed request" ); 
                } 
            } 
            // Spring event mechanism publishes ServletRequestHandlerEvent message , Whether this request is successfully executed or not will publish 
            this message.publishRequestHandledEvent (request, response, startTime, (Throwable) failureCause); 
        } 

    } 
// Abstract method
protected abstract void doService (HttpServletRequest var1, HttpServletResponse var2) throws Exception;

org.springframework.web.servlet.DispatcherServlet#doService

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (this.logger.isDebugEnabled()) {
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
            this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
        }
        //如果是include请求,保存request attribute快照数据,并在finally中进行还原
        Map<String, Object> attributesSnapshot = null;
         / ** 
         * request.getAttribute ("javax.servlet.include.request_uri")! = null 
         * <jsp: incluede page = "xxx.jsp" /> 
         * JSP nested above the tag compiler is also a servlet Use this attribute to determine whether it is an include tag 
         * / 
        if (WebUtils.isIncludeRequest (request)) { 
            attributesSnapshot = new HashMap (); 
            Enumeration attrNames = request.getAttributeNames (); 

            label108: 
            while ( true ) { 
                String attrName; 
                do {
                     if (! attrNames.hasMoreElements ()) {
                         break label108;
                    }

                    attrName = (String)attrNames.nextElement();
                } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
        //保存ApplicationContext 到request
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        //保存localeResolver 到request
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
         // Save themeResolver to request 
        request.setAttribute (THEME_RESOLVER_ATTRIBUTE, this .themeResolver);
         // Save gThemeSource to request 
        request.setAttribute (THEME_SOURCE_ATTRIBUTE, this .getThemeSource ());
         // It seems to solve the redirect 302 band The parameter length problem is first saved to the server and then the 302 redirect only needs to bring a corresponding key 
        FlashMap inputFlashMap = this .flashMapManager.retrieveAndUpdate (request, response);
         if (inputFlashMap! = Null ) { 
            request.setAttribute (INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap (inputFlashMap)); 
        } 

        //Save an empty FlashMap 
        request.setAttribute (OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap ());
         // Save flashMapManager 
        request.setAttribute (FLASH_MAP_MANAGER_ATTRIBUTE, this .flashMapManager); 

        try {
             // <7> Execute processing request 
            this .doDispatch (request, response) ; 
        } finally {
             // Restore snapshot data 
            if (! WebAsyncUtils.getAsyncManager (request) .isConcurrentHandlingStarted () && attributesSnapshot! = null ) {
                 this .restoreAttributesAfterInclude (request, attributesSnapshot); 
            }

        }

    }

Excerpt from: "SpringMVC source code reading-a request main processing flow DispatcherServlet (four)"

Guess you like

Origin www.cnblogs.com/LQBlog/p/12671929.html