SPRINGMVC Source Analysis Interceptor

Source: Internet
Author: User

A thing for a long time, nature will rise from the only use of the level to explore its principle of the level, in the Javaweb springmvc more so, the better the framework, its underlying implementation code is more complex, and in my opinion, an excellent program ape is equivalent to a martial arts master, constantly advanced martial arts cheats, The more inscrutable kungfu, the more to explore its principles, and SPRINGMVC is a very esoteric martial arts cheats.

Speaking of interceptors, said to have to compare with the filter, in this map one does not explain more, simply speaking, the interceptor can be used for the controller layer method implementation before and after.

 

A simple controller layer implementation is listed here first

  

After normal access, let's look at the console.

We all know that Dispatcherservlet is the so-called front-end controller, is the entrance of the entire SPRINGMVC, but there are many doors inside the front controller, we have seen the box containing another box, and this feeling is similar.

Dispatcherservlet inside the process of processing the entrance method is Doservice, first look at the source

 protected voidDoservice (HttpServletRequest request, httpservletresponse response)throwsException {if( This. logger.isdebugenabled ()) {String Attributessnapshot= Webasyncutils.getasyncmanager (Request). Hasconcurrentresult ()? "resumed": "";  This. Logger.debug ("Dispatcherservlet with name \ '" + This. Getservletname () + "\ '" + attributessnapshot + "processing" + request.getmethod () + "Request for [" + Getrequesturi (re Quest) + "]"); }
HashMap attributesSnapshot1=NULL; if(Webutils.isincluderequest (Request)) {ATTRIBUTESSNAPSHOT1=NewHashMap (); Enumeration Inputflashmap=Request.getattributenames (); label108: while(true) {String attrname; Do { if(!inputflashmap.hasmoreelements ()) { Breaklabel108; } attrname=(String) inputflashmap.nextelement (); } while(! This. Cleanupafterinclude &&!attrname.startswith ("Org.springframework.web.servlet")); Attributessnapshot1.put (Attrname, Request.getattribute (attrname)); }} request.setattribute (Web_application_context_attribute, This. Getwebapplicationcontext ()); Request.setattribute (Locale_resolver_attribute, This. Localeresolver); Request.setattribute (Theme_resolver_attribute, This. Themeresolver); Request.setattribute (Theme_source_attribute, This. Getthemesource ()); Flashmap InputFlashMap1= This. Flashmapmanager.retrieveandupdate (request, response); if(InputFlashMap1! =NULL) {Request.setattribute (Input_flash_map_attribute, Collections.unmodifiablemap (INPUTFLASHMAP1)); } request.setattribute (Output_flash_map_attribute,NewFlashmap ()); Request.setattribute (Flash_map_manager_attribute, This. Flashmapmanager); Try { This. Dodispatch (request, response); } finally { if(! Webasyncutils.getasyncmanager (Request). isconcurrenthandlingstarted () && attributesSnapshot1! =NULL) { This. Restoreattributesafterinclude (Request, ATTRIBUTESSNAPSHOT1); } } }

Because the main is to analyze the interceptor first, the rest of the Doservice is not explained first, look at a piece of code

  

 This this. Getservletname () + "\ '" + attributessnapshot + "processing" + request.getmethod () + "Request for [" + Get RequestUri (Request) + "]");

The first paragraph of the console message that I posted is not very similar, which proves thatDoservice is indeed the gateway to the execution of the processing method . But Doservice did not deal with it directly, but instead gave it to dodispatch for specific treatment. Below the source code of the Dodispatch

  

    protected voidDodispatch (HttpServletRequest request, httpservletresponse response)throwsException {httpservletrequest processedrequest=request; Handlerexecutionchain Mappedhandler=NULL; Booleanmultipartrequestparsed =false; Webasyncmanager Asyncmanager=Webasyncutils.getasyncmanager (Request); Try {            Try{Modelandview Err=NULL; Exception dispatchexception=NULL; Try{processedrequest= This. Checkmultipart (Request); Multipartrequestparsed= processedrequest! =request; Mappedhandler= This. GetHandler (Processedrequest); if(Mappedhandler = =NULL|| Mappedhandler.gethandler () = =NULL) {                         This. Nohandlerfound (processedrequest, response); return; } Handleradapter ex= This. Gethandleradapter (Mappedhandler.gethandler ()); String Method=Request.getmethod (); BooleanIsget = "GET". Equals (method); if(Isget | | "HEAD". Equals (method)) {                        LongLastModified =ex.getlastmodified (Request, Mappedhandler.gethandler ()); if( This. logger.isdebugenabled ()) {                             This. Logger.debug ("last-modified value for [" + Getrequesturi (Request) + "] is:" +lastmodified); }                        if((NewServletwebrequest (Request, Response)). Checknotmodified (lastmodified) &&isget) {                            return; }                    }                    if(!Mappedhandler.applyprehandle (processedrequest, response)) {                        return; } Err=Ex.handle (processedrequest, Response, Mappedhandler.gethandler ()); if(asyncmanager.isconcurrenthandlingstarted ()) {return; }                     This. Applydefaultviewname (Request, err);                Mappedhandler.applyposthandle (processedrequest, response, err); } Catch(Exception var19) {dispatchexception=Var19; }                 This. Processdispatchresult (processedrequest, Response, Mappedhandler, err, dispatchexception); } Catch(Exception var20) { This. Triggeraftercompletion (processedrequest, Response, Mappedhandler, VAR20); } Catch(Error var21) { This. Triggeraftercompletionwitherror (processedrequest, Response, Mappedhandler, VAR21); }        } finally {            if(asyncmanager.isconcurrenthandlingstarted ()) {if(Mappedhandler! =NULL) {mappedhandler.applyafterconcurrenthandlingstarted (processedrequest, response); }            } Else if(multipartrequestparsed) { This. Cleanupmultipart (Processedrequest); }        }    }

So the question is, since the request I made is forwarded to Dodispatch for a specific request, then how is the request and controller layer connected, and we'll look at the control layer information

The first paragraph of information is to find the method used on the requested URL/A, the second paragraph is to find the method and return, the third paragraph is to find the controller, and this whole process is done by handlermapping . Yes, although the interceptor works before and after the control layer, we do look for the control layer first , and the Interceptor works.

And find the information we want in the code.

if (! Mappedhandler.applyprehandle (processedrequest, response)) {                        return;                    }

It is also said that this part of the package is the control layer before the implementation of the method, we open this method can see

 BooleanApplyprehandle (HttpServletRequest request, httpservletresponse response)throwsException {handlerinterceptor[] interceptors= This. Getinterceptors (); if(!Objectutils.isempty (interceptors)) {             for(inti = 0; i < interceptors.length; This. Interceptorindex = i++) {Handlerinterceptor Interceptor=Interceptors[i]; if(!interceptor.prehandle (Request, Response, This. Handler)) {                     This. triggeraftercompletion (Request, Response, (Exception)NULL); return false; }            }        }        return true; }

This method first determines whether the interceptor is empty, then uses the for loop to each interceptor Intercepter use Prehandler method, we first notice inside a code

Handlerinterceptor interceptor = interceptors[i];

Each interceptor intercepter must inherit or implement Handlerinterceptor, so the declaration type is applied to polymorphism .

We open the Prehandle method to see

  

 Public Interface handlerinterceptor {    booleanthrows  Exception;     void throws Exception;     void throws Exception;}

Naturally occurring handlerintercetor, which is used in polymorphic only, the superclass can call the subclass method , thus decoupling and extensibility.

After processing the prehandle, the implementation of the control layer method, after processing the advanced line of view processing, when the view is empty, set the default view, and then execute the control layer after the execution of the method, that is, posthandle

  

 This . Applydefaultviewname (Request, err); Mappedhandler.applyposthandle (processedrequest, response, err);

The call to Posthandle is then prehandle similar to the method, and finally the Processdispatchresult method is used to process the results returned, including handling exceptions, rendering the page, The Aftercompletion method that triggers the interceptor.

Since then we have thoroughly analyzed the source of the code about interceptors, in reality, often use more custom interceptors, mainly in:

   1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

  2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;

  3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

  4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

  5、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。

    …………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。

Custom interceptors need to inherit or implement the Handlerinterceptoradapter class, where the code for recording time is posted

  

 Public classStopwatchhandlerinterceptorextendshandlerinterceptoradapter{Private StaticLogger Logger = Logger.getlogger (stopwatchhandlerinterceptor.class); PrivateNamedthreadlocal<long> starttimethreadlocal =NewNamedthreadlocal<long> ("Stopwatch-starttime"); @Override Public BooleanPrehandle (HttpServletRequest request, httpservletresponse response, Object handler)throwsException {LongStartTime =System.currenttimemillis ();        Starttimethreadlocal.set (StartTime); return true; } @Override Public voidAftercompletion (HttpServletRequest request, httpservletresponse response, Object handler, Exception ex)throwsException {LongEndTime =System.currenttimemillis (); LongStartTime =Starttimethreadlocal.get (); String URI=Request.getrequesturi (); Logger.info ("Handle URI:" + uri + "for" + (Endtime-starttime) + "Ms."); }}

In the Dispacher configuration file Plus

<!--global interceptors-    <mvc:interceptors>        <!--intercept all requests--        class= " Scau.zzf.interceptor.interceptor.StopWatchHandlerInterceptor "/>
<mvc:interceptors/>

SPRINGMVC Source Analysis Interceptor

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.