Research code:
Spring configuration file
</>
Java code
@Cacheable (value = "Test", key = "#city") public Map load (String city) {}
"Cache:annotation-driven mechanism"
I thought there would be code to traverse the package to find the class (MyBatis that should have done it), but that's actually the only thing.
Org.springframework.cache.config.annotationdrivencachebeandefinitionparser#parse
public Beandefinition Parse (Element Element, ParserContext parsercontext) {String mode = Element.getattribute ("mode" ); if ("AspectJ" .equals (Mode)) { // Mode=" AspectJ " Registercacheaspect (element, parsercontext); else { // mode= "proxy" registercacheadvisor (element, ParserContext); return null ; }
Regardless of aspectj, normal is to go proxy mode, registered advisor.
"Interception mechanism"
Executed by the agent when the method is executed.
Org.springframework.aop.framework.jdkdynamicaopproxy#invoke
PublicObject Invoke (Object proxy, Method method, object[] args)throwsthrowable {methodinvocation invocation; Object Oldproxy=NULL; BooleanSetproxycontext =false; Targetsource Targetsource= This. Advised.targetsource; Class<?> Targetclass =NULL; Object Target=NULL; Try { if(! This. equalsdefined &&Aoputils.isequalsmethod (method)) { //The target does not implement the Equals (Object) method itself. returnEquals (args[0]); } if(! This. hashcodedefined &&Aoputils.ishashcodemethod (method)) { //The target does not implement the Hashcode () method itself. returnhashcode (); } if(! This. Advised.opaque && Method.getdeclaringclass (). Isinterface () &&Method.getdeclaringclass (). IsAssignableFrom (advised.class)) { //Service invocations on proxyconfig with the proxy config ... returnAoputils.invokejoinpointusingreflection ( This. Advised, method, args); } Object RetVal; if( This. Advised.exposeproxy) { //Make invocation available if necessary.Oldproxy =aopcontext.setcurrentproxy (proxy); Setproxycontext=true; } //May is null. Get as late as possible to minimize the time we "own" the target,//In case it comes from a pool.target =Targetsource.gettarget (); if(Target! =NULL) {Targetclass=Target.getclass (); } //Get The interception chain for this method. list<object> chain = This . Advised.getinterceptorsanddynamicinterceptionadvice (method, Targetclass); //Check Whether we have any advice. If we don ' t, we can fallback on direct//reflective invocation of the target, and avoid creating a methodinvocation. if(Chain.isempty ()) {//We can skip creating a methodinvocation:just invoke the target directly//Note that the final invoker must is an invokerinterceptor so we know it does//Nothing but a reflective operation on the target, and no hot swapping or fancy proxying.RetVal =aoputils.invokejoinpointusingreflection (target, method, args); } Else { //We need to create a method invocation ...invocation =Newreflectivemethodinvocation (proxy, Target, method, args, Targetclass, chain); //Proceed to the Joinpoint through the interceptor chain.RetVal =invocation.proceed (); } //Massage return value if necessary.class<?> ReturnType =Method.getreturntype (); if(RetVal! =NULL&& RetVal = = Target && returntype.isinstance (proxy) &&! Rawtargetaccess.class. IsAssignableFrom (Method.getdeclaringclass ())) { //Special Case:it returned "This" and the return type of the method//Is type-compatible. Note that we can ' t help if the target sets//a reference to itself in another returned object.RetVal =proxy; } Else if(RetVal = =NULL&& returntype! = Void.type &&returntype.isprimitive ()) { Throw NewAopinvocationexception ("Null return value from advice does not match primitive return type for:" +method); } returnRetVal; } finally { if(Target! =NULL&&!targetsource.isstatic ()) { //must has come from Targetsource.Targetsource.releasetarget (target); } if(setproxycontext) {//Restore old proxy.Aopcontext.setcurrentproxy (Oldproxy); } } }
By Getinterceptorsanddynamicinterceptionadvice get the interceptor in effect, the middle goes to a cache, which is ignored here.
Org.springframework.aop.framework.defaultadvisorchainfactory#getinterceptorsanddynamicinterceptionadvice
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 ()) { //traverse registered Advisor 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)) { //Determine if the method is appropriate for the advisor 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; }
Final parsing annotation.
Org.springframework.cache.annotation.annotationcacheoperationsource#determinecacheoperations
protectedCollection<cacheoperation>determinecacheoperations (annotatedelement ae) {Collection<CacheOperation> Ops =NULL; for(Cacheannotationparser Annotationparser: This. Annotationparsers) {Collection<CacheOperation> Annops = annotationparser.parsecacheannotations (AE); if(Annops! =NULL) { if(Ops = =NULL) {Ops=NewArraylist<cacheoperation>(); } ops.addall (Annops); } } returnops; }
Spring Source tracing 3--AOP mechanism