AOP Source Analysis-cglibaopproxy Dynamicadvisedinterceptor

Source: Internet
Author: User
Tags addall

最近新公司在用Spring MVC,跟踪Spring的Service发现是通过动态代理来实现的,而公司的事务是配置在Service层。所以想看下Spring 的AOP的具体实现。本文源码基于Spring 4.0。

We can use debug to track the overall process of a service call, and we can clearly see the process processing:
Cglibaopproxy.intercept method in which the method is passed

 this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

Gets a list intercept chain, and then passes

newmethod, args, targetClass, chain, methodProxy).proceed();

Method executes the corresponding interception chain to perform the processing.
Finally passed,

method, retVal);

Processes the return value and returns.
The whole process is fully implemented by dynamic Proxy mode. The main code is as follows:

@Override         PublicObject Intercept (object proxy,Method Method,Object[]args,Methodproxy Methodproxy)throws Throwable {Object oldproxy = null;            Boolean setproxycontext = false;            Class<?> targetclass = null;            Object target = null;                    try {if (this.advised.exposeProxy) {//Make invocation available if necessary.                    Oldproxy = Aopcontext.setcurrentproxy (proxy);                Setproxycontext = true; }// May  be NULL.Get  as Late  as possible  to Minimize  the  Time We// "own" the Target,inch  Case it comes  from a Pool...Target=Gettarget();                if(Target! = null){targetclass = Target.getclass (); }List<object> chain = This.advised.getInterceptorsAndDynamicInterceptionAdvice ( method, targetclass);Object RetVal;//Check Whether we only has one invokerinterceptor:that is,                //No real advice, but just reflective invocation of the target.                if(Chain.isempty () && modifier.ispublic (Method.getmodifiers())){//We can skip creating a methodinvocation:just invoke the target directly. Note that the final invoker must is a invokerinterceptor, so we know//it does nothing but a refle                    Ctive operation on the target, and no hot//swapping or fancy proxying.                RetVal = Methodproxy.invoke (target, args); }                Else {//We need to create a method invocation ... retVal = new cglibmethodinvocation                (Proxy, Target, method, args, Targetclass, chain, Methodproxy). proceed (); }                RetVal=Processreturntype(proxy, Target, method, RetVal);return retVal; }finally {if (target! = null) {Releasetarget (target); }                if(Setproxycontext){//Restore old proxy.                Aopcontext.setcurrentproxy (Oldproxy); }}        }

The code looks very simple.
Below we can analyze the code line by row.
Method Signature:

publicMethod method, Object[] args, MethodProxy methodProxy) throws Throwable

As you can see, the method is passed in to the proxy object, the method object, the parameters, and the method proxy. Methodproxy contains the method information that we need to be proxied, including the method full signature.

if (this.advised.exposeProxy) {                    if necessary.                    oldProxy = AopContext.setCurrentProxy(proxy);                    settrue;                }

Here the code is to determine whether the agent is available, presumably this means that the code here is not very clear.

target = getTarget();                ifnull) {                    targetClass = target.getClass();                }

Here is the Get target class object.
Down is to get the corresponding chain object.

List<object> chain = This.advised.getInterceptorsAndDynamicInterceptionAdvice ( method, targetclass);     PublicList<object> Getinterceptorsanddynamicinterceptionadvice ( method , Class<?> targetclass)        {Methodcachekey CacheKey = new Methodcachekey (method);        list<object> cached = This.methodCache.get (CacheKey);                    if (cached = = null) {cached = This.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice (            This, method, Targetclass);        This.methodCache.put (CacheKey, cached); }return cached;        }

In this method, the more important thing is to obtain the CacheKey.

/** * Simple wrapper class around a Method.     Used as the key when * caching methods, for efficient equals and hashcode comparisons. */    Private Static  class methodcachekey {        Private FinalMethod method;Private Final intHashcode; Public Methodcachekey(method) { This. method = method; This. hashcode = Method.hashcode (); }@Override         Public Boolean equals(Object Other) {if(Other = = This) {return true; } Methodcachekey OtherKey = (methodcachekey) Other;return( This. method = = Otherkey.method); }@Override         Public int hashcode() {return  This. hashcode; }    }}

This class is relatively simple and defines the corresponding method object, as well as the corresponding hashcode of method.

this.methodCache.get(cacheKey);    /** Cache with Method as key and advisor chain List as value */    privatetransient Map<MethodCacheKey, List<Object>> methodCache;

The corresponding interceptor chain is cached here. If NULL, it is instantiated by factory and placed in the cache.

if(Cached = =NULL) {cached = This. Advisorchainfactory.getinterceptorsanddynamicinterceptionadvice ( This, method, Targetclass); This. Methodcache.put (CacheKey, cached); }@Override     PublicList<object>Getinterceptorsanddynamicinterceptionadvice(advised config, method, class<?> Targetclass) {//This is somewhat tricky ... We have to process introductions first,        //But we need to preserve order in the ultimate list.List<object> interceptorlist =NewArraylist<object> (Config.getadvisors (). length); Class<?> Actualclass = (Targetclass! =NULL? TargetClass:method.getDeclaringClass ());Booleanhasintroductions = hasmatchingintroductions (config, actualclass); Advisoradapterregistry registry = Globaladvisoradapterregistry.getinstance (); for(Advisor advisor:config.getAdvisors ()) {if(AdvisorinstanceofPointcutadvisor) {//Add it conditionally.Pointcutadvisor pointcutadvisor = (pointcutadvisor) advisor;if(config.isprefiltered () | | pointcutadvisor.getpointcut (). Getclassfilter (). Matches (Actualclass))                    {methodinterceptor[] interceptors = registry.getinterceptors (advisor); Methodmatcher mm = Pointcutadvisor.getpointcut (). Getmethodmatcher ();if(Methodmatchers.matches (mm, method, Actualclass, hasintroductions)) {if(Mm.isruntime ()) {//Creating A new object instance in the Getinterceptors () method                            //isn ' t a problem as we normally cache created chains.                             for(Methodinterceptor interceptor:interceptors) {Interceptorlist.add (NewInterceptoranddynamicmethodmatcher (Interceptor, MM)); }                        }Else{Interceptorlist.addall (Arrays.aslist (interceptors)); }                    }                }            }Else if(AdvisorinstanceofIntroductionadvisor) {Introductionadvisor ia = (introductionadvisor) advisor;if(config.isprefiltered () | | ia.getclassfilter (). Matches (Actualclass))                    {interceptor[] interceptors = registry.getinterceptors (advisor);                Interceptorlist.addall (Arrays.aslist (interceptors)); }            }Else{interceptor[] interceptors = registry.getinterceptors (advisor);            Interceptorlist.addall (Arrays.aslist (interceptors)); }        }returnInterceptorlist; }

Although this method is very long, the actual content is relatively simple.
First, get all the pointcuts.

config.getAdvisors()

Determine the different pointcut types and put them in the list.
Executes the corresponding list method.

RetVal =NewCglibmethodinvocation (proxy, Target, method, args, Targetclass, chain, Methodproxy). proceed ();@Override     PublicObjectProceed()throwsThrowable {//We start with an index of-1 and increment early.        if( This. Currentinterceptorindex = = This. Interceptorsanddynamicmethodmatchers.size ()-1) {returnInvokejoinpoint (); } Object Interceptororinterceptionadvice = This. Interceptorsanddynamicmethodmatchers.get (+ + This. Currentinterceptorindex);if(InterceptororinterceptionadviceinstanceofInterceptoranddynamicmethodmatcher) {//Evaluate dynamic method Matcher here:static part would already has            //been evaluated and found to match.Interceptoranddynamicmethodmatcher DM = (interceptoranddynamicmethodmatcher) Interceptororinterceptiona Dvice;if(Dm.methodMatcher.matches ( This. method, This. Targetclass, This. arguments)) {returnDm.interceptor.invoke ( This); }Else{//Dynamic matching failed.                //Skip This interceptor and invoke the next in the chain.                returnProceed (); }        }Else{//It's an interceptor, so we just invoke it:the pointcut would have            //been evaluated statically before this object is constructed.            return((Methodinterceptor) interceptororinterceptionadvice). Invoke ( This); }    }

To process the return value:

method, retVal);                return retVal;

AOP Source Analysis-cglibaopproxy Dynamicadvisedinterceptor

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.