深入学习SpringAOP源码(三)——揭开JDK动态代理和CGLIB代理的神秘面纱

深入解析@EnableAspectJAutoProxy如何激活SpringAOP代理机制 本文深入解析了@EnableAspectJAutoProxy注解如何激活SpringAOP代理机制,详细介绍了其背后的工作原理和实现细节。通过剖析注解触发的连锁反应、代理工厂的创建过程以及代理机制的激活流程,帮助开发者更好地理解和应用SpringAOP。文章还提供了实战中的典型问题排查和性能优化建议,适合需要深入理解SpringAOP的开发者阅读。 阅读详情

前言

版本:【Spring 5.1.4】、【SpringAOP 5.1.4】

经过前两个章节的介绍,已经了解了Spring是如何注册解析AnnotationAwareAspectJAutoProxyCreator,然后AnnotationAwareAspectJAutoProxyCreator又是如何解析通知、创建代理,创建代理的目的又是什么呢?那么接下来本片文章将从深入解析源码的方式并借以《深入学习SpringAOP源码(一)》里Demo为例,来揭开JDK动态代理和CGLIB代理。

深入学习SpringAOP源码(一)——注册AnnotationAwareAspectJAutoProxyCreator
深入学习SpringAOP源码(二)—— 深入AnnotationAwareAspectJAutoProxyCreator

正文

1. CGLIB动态代理

1.1 引入简单的CGLIB例子

在讲解CGLIB动态代理之前,先看一下最简单的CGLIB动态代理的例子。

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class EnhancerDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(EnhancerDemo.class);
        enhancer.setCallback(new MethodInterceptorImpl());
        EnhancerDemo demo = (EnhancerDemo) enhancer.create();
        demo.test();
        System.out.println(demo);
    }
    
    public void test() {
        System.out.println("EnhancerDemo test()");
    }
    
    private static class MethodInterceptorImpl implements MethodInterceptor {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.err.println("Before invoke " + method);
            Object result = methodProxy.invokeSuper(o, objects);
            System.err.println("After invoke" + method);
            return result;
        }
    }
}

运行结果如下:

EnhancerDemo test()
After invokepublic void com.bruis.learnaop.testcglibaop.EnhancerDemo.test()
Before invoke public java.lang.String java.lang.Object.toString()
Before invoke public native int java.lang.Object.hashCode()
After invokepublic native int java.lang.Object.hashCode()
After invokepublic java.lang.String java.lang.Object.toString()
com.bruis.learnaop.testcglibaop.EnhancerDemo$$EnhancerByCGLIB$$413eae0d@53e25b76

可以看到运行结果,除了demo.test()方法之外,System.our.println(demo)也被代理了,首先调用了toString()方法,然后又调用了hashCode,生成的对象为EnhancerDemo的实例,这个类是运行时由CGLIB产生的,Enhancer最关键的步骤就是setCallback()方法来设置拦截器,来拦截代理类的方法。Demo中用到的Enhancer是CGLIB的字节码增强器,用于为无接口的类创建代理proxy,方便对代理类进行拓展,Demo中的代理类就是EnhancerDemo。它的功能与java自带的Proxy类挺相似的,它会根据某个给定的类创建子类,并且非final的方法都带有回调方法。

创建代理对象的几个步骤:

  • 生成代理类的二进制字节码文件
  • 加载二进制字节码,生成Class对象(例如使用Class.forName()方法)
  • 通过反射机制获取实例构造,并创建代理类对象

具体可以查看Enhancer create()源码方法。

1.2 深入代理逻辑源码

先用一张流程图来大致浏览下整个CGLIB的代码逻辑
在这里插入图片描述

回到SpringAOP源码。在《深入学习SpringAOP源码(二)》中,介绍到DefaultAopProxyFactory源码部分

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            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.");
            } else {
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }
}

从createAopProxy()源码中可以看到,创建SpringAOP有两种方式,一、JDK动态代理;二、CGLIB动态代理;点进ObjenesisCglibAopProxy源码,发现它继承了CglibAopFactory

class ObjenesisCglibAopProxy extends CglibAopProxy {
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
        // 通过增强器获取代理类的class对象
        Class<?> proxyClass = enhancer.createClass();
        Object proxyInstance = null;
        if (objenesis.isWorthTrying()) {
            try {
                // 创建代理类实例对象
                proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
            } catch (Throwable var7) {
                logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", var7);
            }
        }

        if (proxyInstance == null) {
            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 var6) {
                throw new AopConfigException("Unable to instantiate proxy using Objenesis, and regular proxy instantiation via default constructor fails as well", var6);
            }
        }

        // 为代理类实例创建回调方法(拦截器链)
        ((Factory)proxyInstance).setCallbacks(callbacks);
        return proxyInstance;
    }
}

createProxyClassAndInstance方法和前面总结的CGLIB创建代理的步骤一样。

继续查看CglibAopProxy是如何准备Enhancer增强器以及创建拦截器链的。

class CglibAopProxy implements AopProxy, Serializable {
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
        }

        try {
            // 获取目标代理类
            Class<?> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
            Class<?> proxySuperClass = rootClass;
            int x;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                Class[] var5 = additionalInterfaces;
                int var6 = additionalInterfaces.length;

                for(x = 0; x < var6; ++x) {
                    Class<?> additionalInterface = var5[x];
                    this.advised.addInterface(additionalInterface);
                }
            }
            // 验证class
            this.validateClassIfNecessary(proxySuperClass, classLoader);
            // 获取增强器
            Enhancer enhancer = this.createEnhancer();
            // 为Enhancer设置类加载器
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader && ((SmartClassLoader)classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }

            // 设置代理类,这一步很关键哦。
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            // 设置strategy策略器
            enhancer.setStrategy(new CglibAopProxy.ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
            Callback[] callbacks = this.getCallbacks(rootClass);
            Class<?>[] types = new Class[callbacks.length];

            for(x = 0; x < types.length; ++x) {
                types[x] = callbacks[x].getClass();
            }
            // 设置回调过滤器
            enhancer.setCallbackFilter(new CglibAopProxy.ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);
            // 创建代理类实例,调用子类的createProxyClassAndInstance()方法
            return this.createProxyClassAndInstance(enhancer, callbacks);
        } catch (IllegalArgumentException | CodeGenerationException var9) {
            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", var9);
        } catch (Throwable var10) {
            throw new AopConfigException("Unexpected AOP exception", var10);
        }
    }
    
    // 获取回调方法
    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        // 获取expose-proxy属性设置
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();
        // 将aop拦截器封装在DynamicAdvisedInterceptor中
        Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
        Object targetInterceptor;
     
        if (exposeProxy) {
            targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
        } else {
            targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedInterceptor(this.advised.getTargetSource());
        }

        Callback targetDispatcher = isStatic ? new CglibAopProxy.StaticDispatcher(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.SerializableNoOp();
        // 添加主要的拦截器链
        Callback[] mainCallbacks = new Callback[]{aopInterceptor, (Callback)targetInterceptor, new CglibAopProxy.SerializableNoOp(), (Callback)targetDispatcher, this.advisedDispatcher, new CglibAopProxy.EqualsInterceptor(this.advised), new CglibAopProxy.HashCodeInterceptor(this.advised)};
        Callback[] callbacks;
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap(methods.length);

            for(int x = 0; x < methods.length; ++x) {
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
                fixedCallbacks[x] = new CglibAopProxy.FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(methods[x].toString(), x);
            }

            callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
            System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
            System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
            this.fixedInterceptorOffset = mainCallbacks.length;
        } else {
            callbacks = mainCallbacks;
        }

        return callbacks;
    }
}

拦截器链在CGLIB中扮演者重要角色,从上面源码中看出拦截器被封装为了DynamicAdvisedInterceptor,那么其核心逻辑就应该在DynamicAdvisedInterceptor中,那看看DynamicAdvisedInterceptor都做了哪些事情。

1.3 DynamicAdvisedInterceptor都做了些啥工作?
    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
        @Nullable
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Object target = null;
            // 获取要拦截的通知源
            TargetSource targetSource = this.advised.getTargetSource();

            Object var16;
            try {
                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }

                target = targetSource.getTarget();
                Class<?> targetClass = target != null ? target.getClass() : null;
                // 获取拦截器链,这里的拦截器链是啥?从哪获取拦截器链?
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    // 如果拦截器链为空,则直接进入拦截器链
                    retVal = methodProxy.invoke(target, argsToUse);
                } else {
                    retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
                }

                retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
                var16 = retVal;
            } finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }

                if (setProxyContext) {
                    AopContext.setCurrentProxy(oldProxy);
                }

            }

            return var16;
        } 
    }
1.4 啥是拦截器链?拦截器链从哪获取?

啥是拦截器链?从哪获取拦截器链?下面继续深入DefaultAdvisorChainFactory方法的getInterceptorsAndDynamicInterceptionAdvice()方法

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
        /*
         * 调用DefaultAdvisorAdapterRegistry构造方法获取通知适配器注册器,包括:
         * 1. MethodBeforeAdviceAdapter
         * 2. AfterReturningAdviceAdapter
         * 3. ThrowsAdviceAdapter
         * 
         * Adapter添加进List中的顺序就是上面的顺序。
         * 
         * GlobalAdvisorAdapterRegistry.getInstance()实际上就是去获取DefaultAdvisorAdapterRegistry中的Adapter
         */
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        // config在这里就是前面所说的ProxyFactory。从ProxyFactory中获取通知
        Advisor[] advisors = config.getAdvisors();
        List<Object> interceptorList = new ArrayList(advisors.length);
        Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();
        Boolean hasIntroductions = null;
        Advisor[] var9 = advisors;
        int var10 = advisors.length;

        for(int var11 = 0; var11 < var10; ++var11) {
            Advisor advisor = var9[var11];
            // 切面型通知
            if (advisor instanceof PointcutAdvisor) {
                // 将通知强转为切面
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    boolean match;
                    if (mm instanceof IntroductionAwareMethodMatcher) {
                        if (hasIntroductions == null) {
                            hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                        }

                        match = ((IntroductionAwareMethodMatcher)mm).matches(method, actualClass, hasIntroductions);
                    } else {
                        match = mm.matches(method, actualClass);
                    }

                    if (match) {
                        /*
                         * 通过通知适配注册器获取方法拦截器,这里返回的是四种拦截器,分别为:
                         * ExposeInvocationInterceptor类型、AspectJAfterAdvice类型、AspectJAroundAdvice类型、MethodBeforeAdviceInterceptor类型
                         * 正好和前面系列文章一、二所描述的四种通知类型一致。
                         */
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        if (mm.isRuntime()) {
                            MethodInterceptor[] var17 = interceptors;
                            int var18 = interceptors.length;

                            for(int var19 = 0; var19 < var18; ++var19) {
                                MethodInterceptor interceptor = var17[var19];
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        } else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            } else if (advisor instanceof IntroductionAdvisor) {// 接口型通知
                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));
            }
        }
    
        /*
         * 这里返回的拦截器链为:
         * 1.ExposeInvocationInterceptor
         * 2.AspectJAfterAdvice
         * 3.AspectJAroundAdvice
         * 4.MethodBeforeAdviceInterceptor
         */
        return interceptorList;
    }
}

在DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法中,主要工作是:

  1. 先获取通知适配器注册器
  2. 将注册器包装为可用的拦截器

在这过程中,DefaultAdvisorAdapterRegistry扮演者非常关键的角色。

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
    private final List<AdvisorAdapter> adapters = new ArrayList(3);
    
    // 在构造方法里注册前置通知、后置通知和异常通知的适配器,
    public DefaultAdvisorAdapterRegistry() {
        this.registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        this.registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        this.registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }

    // wrap方法在AbstractAutoProxyCreator的buildAdvisors方法中已经讲解到了,用于构建Advisor数组,这里就不再讲解
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        if (adviceObject instanceof Advisor) {
            return (Advisor)adviceObject;
        } else if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        } else {
            Advice advice = (Advice)adviceObject;
            if (advice instanceof MethodInterceptor) {
                return new DefaultPointcutAdvisor(advice);
            } else {
                Iterator var3 = this.adapters.iterator();

                AdvisorAdapter adapter;
                do {
                    if (!var3.hasNext()) {
                        throw new UnknownAdviceTypeException(advice);
                    }

                    adapter = (AdvisorAdapter)var3.next();
                } while(!adapter.supportsAdvice(advice));

                return new DefaultPointcutAdvisor(advice);
            }
        }
    }

    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList(3);
        // 获取通知
        Advice advice = advisor.getAdvice();
        // 判断通知是否是MethodInterceptor类型
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor)advice);
        }

        Iterator var4 = this.adapters.iterator();

        while(var4.hasNext()) {
            // 将通知强转为AdvisorAdapter类型
            AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }

        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        } else {
            return (MethodInterceptor[])interceptors.toArray(new MethodInterceptor[0]);
        }
    }

    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }
}

DefaultAdvisorAdapterRegistry类主要负责:

  • 在构造方法里注册前置通知、后置通知和异常通知的适配器
  • 包装Advisor
  • 将Advisor包装为拦截器

既然获取到了拦截器链,那么每个拦截器链都做了些啥呢?回到DynamicAdvisedInterceptor的intercept()方法

1.5 调用拦截器链的proceed方法

视线回到DynamicAdvisedInterceptor的intercept方法,在

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

执行完成之后,chain中存放好了拦截器链,分别是

  1. ExposeInvocationInterceptor
  2. AspectJAfterAdvice
  3. AspectJAroundAdvice
  4. MethodBeforeAdviceInterceptor
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    Object retVal;
    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    // 如果拦截器链为空,则直接进入拦截器链
        retVal = methodProxy.invoke(target, argsToUse);
    } else {
        // 调用拦截器链的proceed方法
        retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
    }
    retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
    var16 = retVal;

后置通知实现逻辑:

public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable {
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object var2;
        try {
            var2 = mi.proceed();
        } finally {
            this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
        }

        return var2;
    }
}
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    
    protected final Object proxy;
    @Nullable
    protected final Object target;
    protected final Method method;
    protected Object[] arguments = new Object[0];
    @Nullable
    private final Class<?> targetClass;
    @Nullable
    private Map<String, Object> userAttributes;
    protected final List<?> interceptorsAndDynamicMethodMatchers;
    private int currentInterceptorIndex = -1;
    
    
    @Nullable
    public Object proceed() throws Throwable {
        
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
            // 获取拦截器链的元素
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
                return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
            } else {
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }
}

这里总结下proceed的逻辑:

  1. 根据索引值获取拦截器链中的拦截器
  2. 要么调用拦截器的invoke方法,要么就调用proceed进行下一轮的递归
  3. proceed方法在这里起到了递归的作用

环绕通知实现逻辑:

public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {
    public Object invoke(MethodInvocation mi) throws Throwable {
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        } else {
            ProxyMethodInvocation pmi = (ProxyMethodInvocation)mi;
            ProceedingJoinPoint pjp = this.lazyGetProceedingJoinPoint(pmi);
            JoinPointMatch jpm = this.getJoinPointMatch(pmi);
            return this.invokeAdviceMethod(pjp, jpm, (Object)null, (Throwable)null);
        }
    }

    protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
        return new MethodInvocationProceedingJoinPoint(rmi);
    }
}
public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable {
    protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
        return this.invokeAdviceMethodWithGivenArgs(this.argBinding(jp, jpMatch, returnValue, t));
    }

    protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
        Object[] actualArgs = args;
        if (this.aspectJAdviceMethod.getParameterCount() == 0) {
            actualArgs = null;
        }

        try {
            ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
            return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
        } catch (IllegalArgumentException var4) {
            throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", var4);
        } catch (InvocationTargetException var5) {
            throw var5.getTargetException();
        }
    }
}

总结下:

  1. AspectJAroundAdvice的invoke方法作用为获取代理方法以及正在处理的切点对象
  2. 将代理方法、切点信息传入AbstractAspectJAdvice的invokeAdviceMethod里进行进一步的参数绑定
  3. invokeAdviceMethodWithGivenArgs方法调用aspectJAdviceMethod.invoke方法,调用AspectJTest类中aroundTest方法

前置通知实现逻辑:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
    private final MethodBeforeAdvice advice;
    
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }
}

public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
    public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
        this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
    }
}

可以注意到:

  1. 代理类的before方法是由AspectJMethodBeforeAdvice类before方法执行的
  2. 在before方法执行完后,调用了MethodInvocation的proceed方法,最终是回到了AspectJAfterAdvice的invoke方法

这整个过程随着AspectJAfterAdvice执行完,整个Demo代码也都走完了。虽然结合着文章开头的时序图,辅以源码来学习整个SpringAOP的运作过程,但也并不能把整个过程描述的非常清楚,下面以本人非常喜欢的一种方式把整个过程展开来。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上面这种文本方式,结合着时序图,能够进一步加深对CGLIB源码逻辑的理解。

在这里插入图片描述

2. JDK动态代理

未完待续…

本篇博文已收录至以下GITHUB中,地址为:https://github.com/coderbruis/JavaSourceCodeLearning

SpringAOP的幕后英雄:揭秘@EnableAspectJAutoProxy如何驱动自动代理机制 本文深入解析了SpringAOP中@EnableAspectJAutoProxy注解的工作原理及其在自动代理机制中的关键作用。通过详细的源码分析和实战案例,揭示了该注解如何激活代理对象生成、扫描切面类以及动态创建代理,帮助开发者高效实现AOP功能。 阅读详情

相关推荐

SpringAOP的幕后英雄:揭秘@EnableAspectJAutoProxy注解的自动代理机制

本文深入解析SpringAOP中@EnableAspectJAutoProxy注解的自动代理机制,揭示其如何通过AspectJAutoProxyRegistrar注册代理创建器,实现Bean的自动代理。文章详细介绍了代理对象的创建过程、与Spring容器的配合机制,以及在实际开发中的典型应用场景,帮助开发者更好地理解和运用SpringAOP的核心功能。

weixin_29248611的博客 175

Java三大特性之——继承初探

继承 什么是继承? 继承(extends),译为延伸、扩充、继承。 继承是Java三大特性之一,可以让子类具有(继承)父类的行为(方法)和特征(属性),也可以在子类中重新定义(重写),以及追加行为和特征。 继承需要的符合关系:is—a的关系;父类更通用更抽象,子类更特殊更具体(因为父类相对于子类来说,父类中有的方法和属性子类中都有,而子类中有的属性和方法父类却未必有,所以说父类更通用抽象,子类更具体特殊)。 继承背后的思想就是基于已经存在的类构建新类,从已存在的类中继承时,就可以重用它的方法和属性,还可以添

WSH0717的博客 302

一款值得关注的开源企业管理ERP系统

盒木ERP是一款开源的现代化企业管理系统,采用前后端分离架构,后端基于Python+Django,前端使用Vue+Ant Design。系统涵盖采购、销售、库存、财务等核心业务模块,支持移动端操作和PDA扫码。具有开源免费、技术先进、功能完善等特点,适合中小企业使用或二次开发。项目提供详细部署指南,支持Docker容器化部署,是学习ERP系统开发和企业数字化转型的优秀选择。

1102

从根上理解Cglib与JDK动态代理

从上面可以看出Cglib和JDK最大的区别在于Cglib实现的动态代理并没有被代理类的实例对象,所有的方法调用都是通过代理类来实现的(子类方法 -> 增强逻辑 -> 子类代理方法 -> 父类方法),而JDK则同时生成了被代理类和代理类的实例对象,然后在代理类中保存有被代理类的引用,目标方法的调用还是被代理对象执行的。下面是代理类的逻辑代码,这个代理类并不是用反编译内存中的代理类来获取得,是作者自己整了一个类似的,如果要获取真正的代理类代码网上方法很多。动态生成代理类的伪代码,省略了很多很多细节。

m0_71777195的博客 947

Flink项目基础配置指南

在大数据处理领域,Apache Flink凭借强大的实时流处理和批处理能力,成为众多开发者的首选工具。在日常工作中,开发Flink Jar任务是常见需求,但每次都需重复配置日志、梳理pom依赖、设置打包插件等,流程繁琐且易出错。为提升开发效率,减少重复劳动,将这些基础配置进行整理归纳十分必要。本文将围绕Flink项目的本地日志配置、pom依赖及插件配置展开详细介绍,为开发者提供一套可直接复用的基础配置方案,助力Flink项目高效开发。在Flink项目中,日志是了解任务运行状态、排查问题的重要依据。本地日志配

qq_42773076的博客 1210

10、数据挖掘与轨迹生成技术:FSSEMiner与CondTraj - GAN的探索

本文介绍了两种先进的数据处理技术:FSSEMiner算法用于从动态属性图中挖掘频繁顺序子图演化模式,揭示如交通流和疾病传播等复杂系统的演化规律;CondTraj-GAN是一种端到端的条件生成对抗网络,能够生成高质量的合成车辆轨迹,解决真实轨迹数据因隐私问题难以获取的挑战。通过实验评估与真实数据集验证,两种技术在可扩展性、实用性及生成质量方面均表现出色,并在交通管理、城市规划、自动驾驶研发等领域具有广泛应用前景。

grafana8visual的博客 86

继承,接口和抽象类

继承,接口和抽象类 Gary 继承 继承Inheritance是继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。 面向对象语言相比于面向过程的编程语言最突出的特点就是变量类型的继承 example:平行四边形为多边形,男人是人类 code: public class Human { public int height; public int weight; public

Garyboyboy的博客 298

手把手保姆级|Python爬取微信公众号文章完整版,反反爬策略拉满,附可运行完整代码(永久可用)

做Python爬虫的朋友都知道,爬取微信公众号文章 绝对是爬虫领域的「香饽饽」也是「硬骨头」。一方面,微信公众号的文章是极具价值的数据源:不管是自媒体从业者做竞品分析、新媒体运营者整理干货、还是个人学习收集资料,都需要批量爬取公众号文章;另一方面,微信的反爬机制堪称全网最严苛之一 ——腾讯对微信生态的风控做到了极致,动态渲染页面、高频IP封禁、Cookie短时效失效、请求头严格校验、自动化工具秒识别、频繁请求直接拉黑,这些反爬手段让90%的爬虫新手望而却步:要么爬了几篇就被封IP,要么Cookie失效爬取中

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2623

子类继承父类方法无法aop_Module子类继承父类想重写父类的方法,但是AOP依然生效...

java.lang.Throwableat com.poppy.modules.ExtendMoudle.ping(ExtendMoudle.java:14)at com.poppy.modules.ExtendMoudle$$NUTZAOP._aop_invoke(ExtendMoudle.java:1)at org.nutz.aop.InterceptorChain.invoke(Interc...

weixin_35399228的博客 307

桌面实施远程光电体积描记法:使用面部视频测量心率的C++详细指南

在现代医疗和健康监测领域,心率是一个非常重要的生理参数,它可以为我们提供关于身体健康状况的重要信息。但是,随着技术的进步,现在我们有了一种新的方法,称为远程光电体积描记法(rPPG),它可以无需与皮肤接触就测量心率。然后,我们从面部颜色的信号序列中提取绿色通道的值,因为绿色通道对于心率的变化最为敏感。在上述代码中,我们使用了OpenCV库,它是一个开源的计算机视觉库,非常适合这种应用。这种变化是由于血液流动引起的,当心脏跳动时,血液流经面部,导致肤色的轻微变化。要实现rPPG,首先需要检测并跟踪人脸。

qq_38334677的博客 608

DFI协议时序

参数名称典型值应用场景关键影响tcmd_lat1-2个时钟周期命令与地址锁存同步地址错误风险tphy_wrlat1-2个时钟周期写操作响应速度写带宽与延迟2-3个时钟周期写操作端到端延迟系统吞吐量1-2个时钟周期连续写命令间隔信号干扰与资源冲突tphy_rdlat1-2个时钟周期读操作响应速度读带宽与延迟trddata_en由CL决定(如0.41 ns)读数据返回时间系统延迟10-20 ps写数据与命令对齐数据丢失风险<1 µs低功耗模式切换。

qq_43134430的博客 5101

继承或实现关系中AOP切面失效的解决方式

转载:继承或实现关系中AOP切面失效的解决方式 https://blog.youkuaiyun.com/wt_better/article/details/84843932 项目定义了一个AbstractController,其中一个方法声明了切面, 子类Controller中需要调用AbstractController中的这个方法,但是切面无法切到AbstractController的方法中,在参考了上面链接后,解决的方法如下: spring配置文件中添加aop:config标签,expose-proxy=“tru

qq_38293154的博客 1108

姿态传感器/陀螺仪之IIS2DLPC 应用驱动程序设计

* 转换为°C单位 (参考温度为25°C,灵敏度为16 LSB/°C) */

corlin6688的博客 218

SpringAop底层源码详解

本文深入剖析了Spring AOP的底层实现机制,从核心概念到源码流程进行了系统拆解。首先介绍了Spring AOP通过自动配置引入AnnotationAwareAspectJAutoProxyCreator作为代理创建器,详细解析了代理对象的创建过程(包括CGLIB代理的生成逻辑)和拦截器链的构建方式。重点分析了切面注解的解析流程、目标方法的匹配机制,以及动态代理执行时通知链的递归调用过程(Before/After等通知的执行顺序)。通过源码追踪,揭示了Spring如何将@Aspect注解转化

2401_89759107的博客 1381

AI自瞄原理剖析(四)从Yolo推理坐标到屏幕坐标:基于FOV视角与焦距的坐标变换与精准瞄准

从Yolo推理框架得到的坐标到屏幕坐标的转换是一个涉及到FOV视角、焦距以及分辨率的复杂过程。通过数学公式,我们可以将推理框坐标反推为游戏内的实际坐标,并最终映射到屏幕坐标系中。利用这些信息,AI自瞄系统能够精确计算出准星从当前位置移动到敌人位置的距离,实现精准的自动瞄准。通过这种方法,AI自瞄系统能够在不同的游戏环境下灵活应对,提供高度精确的操作体验。在AI自瞄系统中,目标检测仅仅是第一步,获取到预测框的坐标后,我们还需要将这些坐标转换为实际屏幕上的精确位置。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1332

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

探秘 SpringAOP:如何让程序在 “横切面” 上优雅起舞

通过对 SpringAOP 源码的深入剖析,我们仿佛揭开了其神秘面纱背后强大的运行机制。从核心概念的理解,到代理模式的巧妙运用,再到源码中各个关键组件的协同工作,我们见证了它如何在不修改原有业务逻辑代码的基础上,精准地切入横切关注点,如日志记录、事务管理、权限验证等。在未来的开发实践中,我们能够更加自信地运用 SpringAOP,充分发挥其优势,构建出高效、健壮且富有弹性的 Java 应用系统,让我们的编程之路在 SpringAOP 的助力下迈向新的高度,迎接更多复杂业务场景的挑战并从容应对。

大家好,我是敖云岚,一个沉迷代码的 “技术玩家”。擅长 Java、C++ 开发,对 MySQL、Redis、RabbitMQ 等技术也颇有研究。博客里既有硬核技术干货,也有诙谐幽默的编程日常分享。愿和你一起,笑着学技术,快乐敲代码! 532

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Spring AOP 总结二

AOP是一种编程思想,用于将程序中的横切关注点(如事务、日志)从业务逻辑代码中分离出来,以提高代码的可重用性和可维护性。Spring框架对其进行了实现。在Spring中AOP是通过代理模式实现的,即在运行时动态的生成一个代理,这个代理类会拦截目标对象的方法调用,并在方法执行前后添加响应的横切逻辑

java_lover20111106的博客 1200

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

SpringMVC--异常处理

给方法上随便写一个Exception,用来接收发生的异常 要携带的异常信息不能给参数位置写Model 返回ModelAndView就行 如果有多个@ExceptionHandler都能处理这个异常,精确优先 全局异常处理与本类同时存在,本类优先 Spring MVC处理异常有3种方式: 1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver; 2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器;.

weixin_41978551的博客 876

子类继承父类方法无法aop_Spring AOP拦截抽象类(父类)中方法失效问题

背景最近工作中需要对组内各个系统依赖的第三方接口进行监控报警,对于下游出现问题的接口能够及时感知.首先我们写了一个Spring AOP注解,用于收集调用第三方时返回的信息.而我们调用第三方的类抽象出一个父类.并在父类的方法中加入我们的自定义注解用于监控日志并打印日志.很多子类继承了这个父类并使用父类中的方法.如:当调用子类的doSomething方法时问题出现了,发现Spring AOP没有拦截d...

weixin_35817272的博客 3250

对继承类方法切面失效

实际应用中,controller一般都会去继承一个基础类,该基础类一般都是都对缓存、用户信息、返回值的一些通用处理。现在我想针对这个基础类的一个方法进行切面,处理一些东西,遇到的第一个问题就是,切面的切入的方法是 public 的,但通用基础类,人家本来也只是供其继承者使用的,所以通常方法的最大权限也不过是 protect , 所以其实这里就应该把我劝退了,但我没管,直接将方法改成了public。 然后信心满满地进行下一步,发现切面完全没作用,百度了一天,以为是配置不对,各种改,就是不见效果。然后找到下面

zwy 964

java 重载、重写、重构的区别

1.重载 构造函数是一种特殊的函数,使用构造函数的目的是用来在对象实例化时初始化对象的成员变量。由于构造函数名字必须与类名一致,我们想用不同的方式实例化对象时,必须允许不同的构造方法同时存在,这就用到了重载。 重载虽然起源于构造方法,但是在普通方法中也可以使用方法的重载。方法的重载就是在同一个类中允许同时存在多个同名方法,只要这些方法的参数类型、个数、顺序不同即可。 package co...

weixin_33720078的博客 339

子类继承父类方法无法aop_spring中aop不生效的几种解决办法

先看下这个问题的背景:假设有一个spring应用,开发人员希望自定义一个注解@Log,可以加到指定的方法上,实现自动记录日志(入参、出参、响应耗时这些)package com.cnblogs.yjmyzz.springbootdemo.aspect;import java.lang.annotation.ElementType;import java.lang.annotation.Retenti...

weixin_39555415的博客 1411

springBoot 全局异常处理

前言 本demo的github链接: https://github.com/heruideid/springBoot_demo/tree/master 我的公众号「Rui的后端手册」,先赞后看,月入百万 代码分层 springBoot开发的web项目中,强调分层的概念,一个完整的项目一般会划分出controller层和service层。 controller层负责**service层业务方法的路由和参数的校验**。应用跑起来后,根据收到请求的url和请求类型调用对应controller层的方法处理。con

weixin_46598778的博客 417

利用Spring AOP中的引入解决java无法多继承问题

我们知道在java中一个类无法继承多个基类,而有时候,你可能有一组共享公共行为的类,在OOP中,它们必须扩展 相同的基类或者实现相同的接口。这个问题可以用AOP模块化的一个横切关注点。Introduction是AOP中的一种特殊 通知,它允许为一个接口提供实现类使对象动态地实现接口。这样看上去就像使对象在运行时扩展了实现类。而且,你 可以用多个实现类将多个接口同时引入对象。这可以实现与多重继

David_Tsai23的专栏 1468

spring-aop之cglib代理生成逻辑

查看aop源码做个简单的笔记,记录aop之cglib代理生成流程,包含两部分进行说明,一个是cglib把增强的通知植入的过程,还有一个是调用方法时执行的过程 一.把通知植入到cglib代理的过程 3:是把aop增强逻辑和目标方法添加到代理,会创建 targetDispatcher(StaticDispatcher) aopInterceptor(DynamicAdvisedInterceptor) 包含了增强的逻辑 targetInterceptor(StaticUnadvisedExpos

Aqibk的博客 312

AOP六个专业术语在代码中的体现

AOP是我们在做项目拓展时,时常用到的技术点,这也是我们面向切面编程的核心所在,AOP的使用还是很方便的,但里面的细节往往会被忽略,即六个专业术语的使用位置,今天小编为大家分享一下,aop的6个专业术语的使用位置。 首先我们了解一下概念,源自百度百科: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容...

Elsa~的博客 630
上一篇: 深入学习SpringAOP源码(二)—— 深入AnnotationAwareAspectJAutoProxyCreator
下一篇: 一篇文章让你快速弄清Java虚拟机的GC过程
CoderBruis
博客等级 码龄10年 4444粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值