Spring AOP source code analysis

AOP source code analysis

Xml file loading process

  1. java code

    // Section class
    public class LogUtil {
    
    	public void before(){
    		System.out.println("before~~~");
    	}
    
    	public void after(){
    		System.out.println("after~~~");
    	}
    
    	public void afterReturning(){
    		System.out.println("after returning~~~");
    	}
    
    
    }
    
    
    
    // Ordinary class, which needs to be represented
    public class Children {
    
    	public void cry(){
    		System.out.println("wuwuwu............");
    	}
    
    	public void smile(){
    		System.out.println("hahaha.............");
    	}
    
    }
    
  2. Profile content

    <bean id="logUtil" class="com.xwdx.start.springaop.LogUtil"></bean>
    
    <bean id="children" class="com.xwdx.start.springaop.Children"></bean>
    
    <aop:config>
        <aop:aspect ref="logUtil">
            <aop:pointcut id="myPointcut" expression="execution(* *.*(..))"/>
            <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
            <aop:after method="after" pointcut-ref="myPointcut"></aop:after>
            <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"></aop:after-returning>
        </aop:aspect>
    </aop:config>
    
  3. Parse the aop tag and register the BeanDefinition in the Factory. After this step, the xml is parsed to BeanDefinition and the parsing is completed

    <aop:config>Tags, parsing to AspectJAwareAdvisorAutoProxyCreator Object, which is inherited from SmartInstantiationAwareBeanPostProcessor´╝îbean This is called in the previous part of initialization BeanPostProcessor
    key=  org.springframework.aop.config.internalAutoProxyCreator
    valud=org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator
    <aop:before> after after-returning after-throwing around And other labels, all registered AspectJPointcutAdvisor object
    key=org.springframework.aop.aspectj.AspectJPointcutAdvisor#0 because there are multiple key s, 0, 1 and 2 are superimposed in turn
    value=org.springframework.aop.aspectj.AspectJPointcutAdvisor
    <aop:pointcut>Label resolution to  AspectJExpressionPointcut object
    

    First register the AspectJAwareAdvisorAutoProxyCreator object, then register the AspectJPointcutAdvisor object, and finally register the AspectJExpressionPointcut object

AOP object processing procedure

BeanDifinition of several objects was created earlier, and these beans will be created later when initializing beans

registerBeanPostProcessors(beanFactory) of refresh() method; This method creates the AspectJAwareAdvisorAutoProxyCreator object

In the process of creating a bean, object bean = resolvebeforeinstance (beanname, mbdtouse);

This method will call the applybeanpostprocessorsbeforeinstance method of the BeanPostProcessor that implements the instantiaawarebeanpostprocessor

Because the AspectJAwareAdvisorAutoProxyCreator object was created earlier, the applybeanpostprocessorsbeforeinstance method of AspectJAwareAdvisorAutoProxyCreator will be called. The source code is as follows. shouldSkip is the core method

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // shouldSkip is the core method, which will create the objects required by AOP
        // The AspectJPointcutAdvisor object contains the AbstractAspectJAdvice object
        //   -AbstractAspectJAdvice contains the following three objects
        //     -Method object
        //     - AspectJExpressionPointcut
        //     - AspectInstanceFactory
        // After the shouldSkip method is executed, the above objects will be created
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

Agent generation process

After several objects of AOP are processed, a proxy object will be generated when calling the Children object

A method initializeBean(beanName, exposedObject, mbd) after populating the attribute populate method; This method creates a proxy for the Children object

initializeBean method will call wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

Call wrapIfNecessary method of AbstractAutoProxyCreator class. Core code:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.   This method is also very important. It constructs the Advisor array
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // Core methods for creating proxy objects
        Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}
// getAdviceAndAdvisorsForBean method will jump to findEligibleAdvisors method, in which extendAdvisors is very important
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // Query the existing Advisor in beanFactory. Since there is already cached aspectjpointcutadvisor in the previous initialization #0-2,
    // Here, you will get the three cacheddadvisorbeannames from the cache, and then use beanfactory Getbean() initialization
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // Query the qualified Advisors collection and do some verification to see if it can be used as a proxy for the current object to filter out unwanted Advisors
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // Expanding Advisors will add exposeinvocationinterceptor. To the index position 0 of the list Advisor, click along this method to see
    // Here you will jump to the extendAdvisors method of the AspectJAwareAdvisorAutoProxyCreator class
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // This sort uses topological sort, directed acyclic graph
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

Note the class diagram of extendAdvisors

Write briefly here

Aspectjawareaadvisor autoproxycreator inherits from abstractadvisor autoproxycreator inherits from AbstractAutoProxyCreator

The parsed tag initializes the AspectJAwareAdvisorAutoProxyCreator object, and the postProcessAfterInitialization() method belongs to the AbstractAutoProxyCreator class,

getAdvicesAndAdvisorsForBean() method and findEligibleAdvisors() method belong to AbstractAdvisorAutoProxyCreator class,

Then jump to the extendAdvisors() method, which belongs to AspectJAwareAdvisorAutoProxyCreator

// createProxy source code
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // The advisors here are AspectJPointcutAdvisor objects obtained by parsing aop tags, 
    // By default, the first one is exposeinvocationinterceptor ADVISOR
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // Adding advisors to the advisors collection of proxyFactory is critical and will be used later
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // After setting some values earlier, you will go to the core methods of common proxy objects
    return proxyFactory.getProxy(getProxyClassLoader());
}

proxyFactory.getProxy(getProxyClassLoader()) method

public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

protected final synchronized AopProxy createAopProxy() {
    // createAopProxy method. this is proxyfactory
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

The number of times is divided into two steps: one is createAopProxy and the other is getProxy method

createAopProxy method of DefaultAopProxyFactory

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {    // The config here is the proxyFactory object above. The construction method of JDK and cglib proxy objects is passed in, and if (config. Iseptimize() | | config. Is omitted isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {        Class<?> targetClass = config.getTargetClass();        if (targetClass == null) {            throw new AopConfigException("TargetSource cannot determine target class: " +                                          "Either an interface or a target is required for proxy creation.");        }        //  If there is an interface or proxy object, use JDK dynamic proxy if (targetclass. Isinterface() | proxy isProxyClass(targetClass)) {            return new JdkDynamicAopProxy(config);        }        //  Otherwise, use cglib dynamic proxy return new objenesiscglibaopproxy (config);} else {        return new JdkDynamicAopProxy(config);    }}

Here we mainly look at the CGLIB dynamic proxy process, the getProxy method of ObjenesisCglibAopProxy, which inherits from CglibAopProxy

// CglibAopProxy class getProxy method source code public object getProxy (@ nullable classloader classloader) {try {/ /...... Omit part of the code.................... / / configure cglib enhancer... Enhancer enhancer = createenhancer(); if (classloader! = null) {enhancer.setclassloader (classloader); if (classLoader instanceof SmartClassLoader &&                ((SmartClassLoader) classLoader). isClassReloadable(proxySuperClass)) {                enhancer.setUseCache(false);            }        }         enhancer. setSuperclass(proxySuperClass);        //  Two interfaces, SpringProxy and advised enhancer, are generally added here setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));         enhancer. setNamingPolicy(SpringNamingPolicy.INSTANCE);         enhancer. setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));        //  Getcallbacks is the core method. Callback [] callbacks = getcallbacks (rootclass); Class<?> [] types = new Class<?> [callbacks.length];         for (int x = 0; x < types.length; x++) {            types[x] = callbacks[x].getClass();        }        //  fixedInterceptorMap only populated at this point, after getCallbacks call above        enhancer. setCallbackFilter(new ProxyCallbackFilter(            this.advised.getConfigurationOnlyCopy(), this. fixedInterceptorMap, this. fixedInterceptorOffset));         enhancer. setCallbackTypes(types);        //  Generate the proxy class and create a proxy instance.        //  Create object method return createproxyclassandinstance (enhancer, callbacks);} catch (CodeGenerationException | IllegalArgumentException ex) {        throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +                                     ": Common causes of this problem include using a final class or a non-visible class",                                     ex);    }     catch (Throwable ex) {        // TargetSource.getTarget() failed        throw new AopConfigException("Unexpected AOP exception", ex);    }}//  Only paste the core code private callback [] getcallbacks (class <? > rootclass) throws exception {/ / the advised here is the proxyFactory object in front, and the advisor attribute in it is the advisor set resolved in front. Callback aoptinterceptor = new dynamicadisadvidedinceptor (this. Advised); / / choose a "straight to target" interceptor (used for calls that are    // unadvised but can return this).  May be required to expose the proxy.     Callback targetInterceptor;     if (exposeProxy) {        targetInterceptor = (isStatic ?                             new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :                             new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));    }     else {        targetInterceptor = (isStatic ?                             new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :                             new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));    }    //  Choose a "direct to target" dispatcher (used for    // unadvised calls to static targets that cannot return this).     Callback targetDispatcher = (isStatic ?                                 new StaticDispatcher(this.advised.getTargetSource(). getTarget()) : new SerializableNoOp());    //  For this callback array, the first one is dynamic advised interceptor, the second one is staticunadvisedinterceptor, / / there are others later, Put it into this array once and return callback [] mainCallbacks = new callback [] {aopinterceptor, / / for normal advice targetinterceptor, / / invoke target without considering advice, if optimized new serializablenoop() ,  // no override for methods mapped to this        targetDispatcher, this. advisedDispatcher,        new EqualsInterceptor(this.advised),        new HashCodeInterceptor(this.advised)    };     Callback[] callbacks;    // ......... Assign mainCallbacks to callbacks, and there are some judgments return callbacks;}
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {    Class<?> proxyClass = enhancer.createClass();    Object proxyInstance = null;    if (objenesis.isWorthTrying()) {        try {            proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());        }        catch (Throwable ex) {            logger.debug("Unable to instantiate proxy using Objenesis, " +                         "falling back to regular proxy construction", ex);        }    }    if (proxyInstance == null) {        // Regular instantiation via default constructor...         try {            Constructor<?> ctor = (this.constructorArgs != null ?                                   proxyClass.getDeclaredConstructor(this.constructorArgTypes) :                                   proxyClass.getDeclaredConstructor());            ReflectionUtils.makeAccessible(ctor);            proxyInstance =  (this.constructorArgs != null ?                             ctor.newInstance(this.constructorArgs) : ctor. newInstance());        }         catch (Throwable ex) {            throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +                                         "and regular proxy instantiation via default constructor fails as well", ex);        }    }    //  The previous step is the process of cglib generating and initializing the dynamic proxy class. This step is the key step. Set the callbacks, which is the callback array obtained by the getCallbacks method above. / / at this step, the object has been created ((factory) proxyinstance) setCallbacks(callbacks);     return proxyInstance;}

Content of class file generated by CGLIB

View the bytecode class file generated by cglib

Add the following settings to save the class file locally

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\project-springframework\spring-framework\cglibproxy");

// The proxy class decompiles the code and the smile method, so it can be predicted that the final call is CGLIB$CALLBACK_0.intercept() method, cglib $callback_ What is 0? Look at the following method: public class Children$$EnhancerBySpringCGLIB$bde0238 extends Children implements SpringProxy, Advised, Factory{    public final void smile() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }        if (var10000 != null) {            var10000.intercept(this, CGLIB$smile public class children $$enhancerbyspringcglib $$5bde0238 extends children implements springproxy, advised,  Factory{    public final void smile() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }         if (var10000 != null) {            var10000.intercept(this, CGLIB$smile$0$Method, CGLIB$emptyArgs, CGLIB$smile$0$Proxy);        }  else {            super.smile();        }    }         public final void cry() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }         if (var10000 != null) {            var10000.intercept(this, CGLIB$cry$1$Method, CGLIB$emptyArgs, CGLIB$cry$1$Proxy);        }  else {            super.cry();        }    }         public final boolean equals(Object var1) {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_5;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_5;        }         if (var10000 != null) {            Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);             return var2 == null ?  false : (Boolean)var2;        }  else {            return super.equals(var1);        }    }    //  Setcallbacks $Method, CGLIB$emptyArgs, CGLIB$smile public class children $$enhancerbyspringcglib $$5bde0238 extends children implements springproxy, advised,  Factory{    public final void smile() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }         if (var10000 != null) {            var10000.intercept(this, CGLIB$smile$0$Method, CGLIB$emptyArgs, CGLIB$smile$0$Proxy);        }  else {            super.smile();        }    }         public final void cry() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }         if (var10000 != null) {            var10000.intercept(this, CGLIB$cry$1$Method, CGLIB$emptyArgs, CGLIB$cry$1$Proxy);        }  else {            super.cry();        }    }         public final boolean equals(Object var1) {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_5;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_5;        }         if (var10000 != null) {            Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);             return var2 == null ?  false : (Boolean)var2;        }  else {            return super.equals(var1);        }    }    //  Setcallbacks $Proxy);        } else {            super.smile();        }    }        public final void cry() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }        if (var10000 != null) {            var10000.intercept(this, CGLIB$cry $Method, CGLIB$emptyArgs, CGLIB$cry $Proxy);        } else {            super.cry();        }    }        public final boolean equals(Object var1) {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_5;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_5;        }        if (var10000 != null) {            Object var2 = var10000.intercept(this, CGLIB$equals $Method, new Object[]{var1}, CGLIB$equals $Proxy);            return var2 == null ? false : (Boolean)var2;        } else {            return super.equals(var1);        }    }    // setCallbacks method / / in the previous step, create proxyclassandinstance. The last two lines of code call setcallbacks method / / ((factory) proxyinstance) setCallbacks(callbacks);    //  return proxyInstance;    //  CGLIB$CALLBACK_ 0 is the dynamic advised interceptor, //The above smile and cry methods will call the intercept method of dynamicadiscedeinterceptor. Public void setcallbacks (callback [] VAR1) {this. Cglib $callback_0 = (methodinterceptor) VAR1 [0]; this. Cglib $callback_1 = (methodinterceptor) VAR1 [1]; this. Cglib $callback_2 = (NOOP) VAR1 [2]; this. Cglib $callback_3 = (dispatcher) var1[3];         this. CGLIB$CALLBACK_ 4 = (Dispatcher)var1[4];         this. CGLIB$CALLBACK_ 5 = (MethodInterceptor)var1[5];         this. CGLIB$CALLBACK_ 6 = (MethodInterceptor)var1[6];    }}

AOP execution process

From the above logic, you can see that when you execute the smile method of Children object, you will go to the intercept method of dynamic advised interceptor (basic knowledge of CGLIB dynamic agent)

Source code of dynamic advised interceptor intercept method

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {    Object oldProxy = null;    boolean setProxyContext = false;    Object target = null;    // Wrapper class of proxy target object Targetsource Targetsource = this advised. getTargetSource();     try {        if (this.advised.exposeProxy) {            // Make invocation available if necessary.            oldProxy = AopContext.setCurrentProxy(proxy);            setProxyContext = true;        }        //  Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...         target = targetSource. getTarget();         Class<?>  targetClass = (target != null ? target.getClass() : null);        //  The core method is to obtain the chain set. The AOP execution process uses the responsibility chain mode. This method is used to build the execution chain list < Object > chain = this advised. getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);         Object retVal;        //  Check whether we only have 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 be an InvokerInterceptor, so we know            // it does nothing but a reflective operation on the target, and no hot            // swapping or fancy proxying.            Object [] argsToUse = AopProxyUtils. adaptArgumentsIfNecessary(method, args);             retVal = methodProxy. invoke(target, argsToUse);        }         Else {/ / we need to create a method invocation... / / execute the core method retval = new cglibmethodinvocation (proxy, target, method, args, targetclass, chain, methodproxy). Processed();} retVal = processReturnType(proxy, target, method, retVal);         return retVal;    }     finally {        if (target != null && !targetSource.isStatic()) {            targetSource.releaseTarget(target);        }         if (setProxyContext) {            // Restore old proxy.            AopContext.setCurrentProxy(oldProxy);        }    }}

List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Method returns an array of methodinterceptors

In this example, ExposeInvocationInterceptor AfterReturningAdviceInterceptor AspectJAfterAdvice MethodBeforeAdviceInterceptor from front to back

With this chain, in the processed method

// The processed method of CglibMethodInvocation class private static class CglibMethodInvocation extends ReflectiveMethodInvocation {public object processed() throws throwable {try {/ / call the parent class directly, and the processed return of ReflectiveMethodInvocation is super. Processed();} catch (RuntimeException ex) {            throw ex;        }         catch (Exception ex) {            if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||                KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {                // Propagate original exception if declared on the target method                // (with callers expecting it) .  Always propagate it for Kotlin code                // since checked exceptions do not have to be explicitly declared there.                 throw ex;            }             else {                // Checked exception thrown in the interceptor but not declared on the                // target method signature -> apply an UndeclaredThrowableException,                // aligned with standard JDK dynamic proxy behavior.                throw new UndeclaredThrowableException(ex);            }        }    }}

The source code of the proceed method of the ReflectiveMethodInvocation class

public Object proceed() throws Throwable {    // We start with an index of -1 and increment early.    // interceptorsAndDynamicMethodMatchers is the chain built above. The default value of currentinterceptorindex is - 1 if (this. Currentinterceptorindex = = this. Interceptorsanddynamicmethodmatchers. Size() - 1) {/ / if all methodinterceptors in the chain are executed, execute the method of the original class return invokejoinpoint();} Object interceptorOrInterceptionAdvice =        this. interceptorsAndDynamicMethodMatchers. get(++this.currentInterceptorIndex);     if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {        // Evaluate dynamic method matcher here: static part will already have        // been evaluated and found to match.        InterceptorAndDynamicMethodMatcher dm =            (InterceptorAndDynamicMethodMatcher)  interceptorOrInterceptionAdvice;         Class<?>  targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());         if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {            return dm.interceptor.invoke(this);        }         else {            // Dynamic matching failed.            // Skip this interceptor and invoke the next in the chain.            return proceed();        }    }     else  {/ / it's an interceptor, so we just invoke it: the pointcut will have / / be evaluated statically before this object was constructed. / / the invoke method starts to execute the chain, and then calls the invoke method of each MethodInterceptor object in the chain collection. / / note this. Pass the current class as a parameter, and then each method The odinterceptor calls MI Processed will return to the current method return ((MethodInterceptor) interceptorinterceptionadvice) invoke(this);    }}

ExposeInvocationInterceptor execution process

public Object invoke(MethodInvocation mi) throws Throwable {    // Invocation is a ThreadLocal property, which is used to put the object of ReflectiveMethodInvocation class into ThreadLocal. Methodinvocation oldinvocation = invocation get();     invocation. set(mi);     Try {/ / go back to the processed method of ReflectiveMethodInvocation. / / you can see that the index currentInterceptorIndex of ReflectiveMethodInvocation is 0, / / and then this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex) ;        //  Get the second MethodInterceptor, AfterReturningAdviceInterceptor, and start executing the invoke method return Mi of AfterReturningAdviceInterceptor proceed();    }     finally {        invocation.set(oldInvocation);    }}

AfterReturningAdviceInterceptor execution process

public Object invoke(MethodInvocation mi) throws Throwable {    // Continue to execute the processed method of reflective methodinvocation, and then execute the afterreturning method after the execution is completed. Therefore, first jump to the invoke method of AspectJAfterAdvice, object retval = MI proceed();     this. advice. afterReturning(retVal, mi.getMethod(), mi. getArguments(), mi. getThis());     return retVal;}

AspectJAfterAdvice execution process

public Object invoke(MethodInvocation mi) throws Throwable {    try {        // Continue to execute the processed method of reflective methodinvocation, / / jump to the invoke - > methodbeforeadviceinterceptor return Mi of the next MethodInterceptor in the chain proceed();    }     Finally {/ / after the execution is completed, execute the invokeAdviceMethod(getJoinPointMatch(), null, null) in finally; the method invokeAdviceMethod(getJoinPointMatch(), null, null);}}

MethodBeforeAdviceInterceptor execution procedure

public Object invoke(MethodInvocation mi) throws Throwable {    // Because it is before, call the before enhancement method first, and then return to the processed method of ReflectiveMethodInvocation. / / the before method here is to call the < AOP: before method = "before" pointcut ref = "mypointcut" > < / AOP: before > configured method / / - > the before method of logutil this advice. before(mi.getMethod(), mi. getArguments(), mi. getThis());    //  Back to MI After the processed () method, since the index has reached the last, return invokejoinpoint() will be executed// Invokejoinpoint() method is to call the original proxy method, such as Children's smile method. After execution, it will execute the MethodInterceptor above in turn. / / execute the final code block of the invoke method of AspectJAfterAdvice, that is, < AOP: after > / / execute the advice of the invoke method of AfterReturningAdviceInterceptor Afterreturning, that is, the configured < AOP: after returning > / / execute the invalid code block of the invoke method of ExposeInvocationInterceptor. The entire AOP is completed. Return MI proceed();}

supplement

Since the after throwing process is not configured in this example, once again, after throwing is configured, the AspectJAfterThrowingAdvice object will be added to the chain

Let's take a look at the invoke method of AspectJAfterThrowingAdvice

public Object invoke(MethodInvocation mi) throws Throwable {    try {        // The same processing logic as other methodinterceptors returns MI proceed();    }     Catch (throwable Ex) {if (shouldinvokeonthrowing (Ex)) {/ / execute the enhanced method invokeadvicemethod (getjoinpointmatch(), null, ex) of after throwing configuration;} throw ex;    }}

summary

The AOP execution process is complex. Briefly summarize the basic steps:

  1. Load xml, parse tags, create some basic objects,
  2. When instantiating a spring bean, call the BeanPostProcessor to process the bean that needs to be proxied
  3. Generate proxy objects through jdk or cglib
  4. When calling the proxy object method, execute the intercept method of dynamicadiscedeinterceptor, which will build a MethodInterceptor chain and execute the invoke method in turn

Added by ndjustin20 on Fri, 24 Dec 2021 02:54:36 +0200