备战面试日记(4.2.18)- (框架.Spring【四】之 Spring AOP 代理对象的方法调用与增强)

本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试。

记录日期:2022.2.5

大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习。

框架原理 - Spring(四) 之 Spring AOP 代理对象的方法调用与增强

当前使用 Spring 版本 5.2.5.RELEASE

代理对象的方法调用与增强

JDK动态代理调用

JdkDynamicAopProxy 中实现了 InvocationHandler 接口,也就是当 Proxy 对象的代理方法被调用时, JdkDynamicAopProxy 的的 invoke() 方法作为 Proxy 对象的回调函数被触发,从而通过 invoke() 的具体实现,来完成对目标对象方法调用的拦截或者说功能的增强工作。

JdkDynamicAopProxy 中,invoke() 方法是JDK动态代理的调用入口方法:

  1. 通过 getInterceptorsAndDynamicInterceptionAdvice() 方法获取适合该方法的拦截器链集合。
  2. 创建一个 ReflectiveMethodInvocation 方法调用服务,随后使用 ReflectiveMethodInvocation 调用 proceed() 方法,通过责任链模式方法递归调用来实现方法的代理和增强的逻辑。
// AOP配置,即proxyFactory对象
private final AdvisedSupport advised;

//  接口集合中是否存在某个集合有equals方法
private boolean equalsDefined;
// 接口集合中是否存在某个集合有hashCode方法
private boolean hashCodeDefined;

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    // 是否设置代理上下文
    boolean setProxyContext = false;

    // 获取TargetSource,targetSource实际上就是对目标对象实例进行封装的对象
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        // 1. 如果代理接口集中不存在equals方法,并且当前拦截的方法是equals方法,说明目标类没有实现接口的equals方法本身
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // 1.1 调用JdkDynamicAopProxy自己的equals方法比较,因此可能会产生问题
            return equals(args[0]);
        }
        // 2. 如果代理接口集中不存在hashCode方法,并且当前拦截的方法是hashCode方法,说明目标类没有实现接口的hashCode方法本身
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // 2.1 调用JdkDynamicAopProxy自己的hashCode方法比较,因此可能会产生问题
            return hashCode();
        }
        // 3. 如果当前拦截的方法属于DecoratingProxy接口,该方法是getDecoratedClass方法
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // 3.1 调用AopProxyUtils.ultimateTargetClass方法返回代理的最终目标类型,没有调用实现getDecoratedClass方法
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 4.1.1 如果opaque属性为false(默认false)
        else if (!this.advised.opaque &&
                 // 4.1.2 并且当前拦截的方法属于一个接口
                 method.getDeclaringClass().isInterface() &&
                 // 4.1.3 并且方法当前拦截的方法所属的接口是Advised接口或者Advised的父接口
                 method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // Service invocations on ProxyConfig with the proxy config...
            // 4.2 反射调用原始方法
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        // 5. 如果exposeProxy属性为true(默认false),表示需要暴露代理对象
        // 可通过<aop:config/>标签的expose-proxy属性或者@EnableAspectJAutoProxy注解的exposeProxy属性控制
        if (this.advised.exposeProxy) {
            /*
            5.1 将proxy也就是代理对象,通过AopContext.setCurrentProxy设置到AopContext内部的ThreadLocal线程本地变量中
            这样我们就能在原始方法中通过AopContext.currentProxy()方法直接获取当前的代理对象
            这个设置主要用来解决同一个目标类的方法互相调用时代理不生效的问题
            */
            oldProxy = AopContext.setCurrentProxy(proxy);
            // 5.2 setProxyContext置为true
            setProxyContext = true;
        }

        // 6. 获取原始目标对象,也就是被代理的对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 7. 获取匹配当前方法的Advisor中的拦截器链列表,用于拦截当前方法并进行增强
        // 对于AnnotationAwareAspectJAutoProxyCreator和AspectJAwareAdvisorAutoProxyCreator自动代理创建者
        // 第一个拦截器就是ExposeInvocationInterceptor,它是后面在extendAdvisors中加入进去的,其规则匹配所有方法
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // 8. 如果针对当前方法的拦截器链为空
        if (chain.isEmpty()) {
            // 8.1 如有必要,根据给定方法中的需要参数类型调整参数数组类型
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 8.2 直接反射通过目标类调用当前方法
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        // 9. 如果针对当前方法的拦截器链不为空
        else {
            // 9.1 创建一个MethodInvocation方法调用服务,参数为代理对象、目标对象、方法参数、目标类型、该方法的拦截器链集合
            MethodInvocation invocation =
                new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 9.2 调用方法调用服务的proceed方法,进行方法的代理和增强,核心方法
            retVal = invocation.proceed();
        }

        // 对于方法返回值进行必要的类型转换,比如返回代理对象
        
        // 10. 获取方法返回值类型
        Class<?> returnType = method.getReturnType();
        
        // 11.1.1 如果执行结果不为null
        if (retVal != null &&
            // 11.1.2 并且返回值等于目标对象
            retVal == target &&
            // 11.1.3 并且返回值类型不是Object
            returnType != Object.class &&
            // 11.1.4 并且返回值类型和代理类型兼容
            returnType.isInstance(proxy) &&
            // 11.1.5 并且方法所属的类的类型不是RawTargetAccess类型及其子类型
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // 11.2 返回值设置为当前代理对象,也就是返回代理对象
            retVal = proxy;
        }
        // 12.1.1 如果返回值为null
        else if (retVal == null &&
                 // 12.1.2 并且返回值类型不是void
                 returnType != Void.TYPE &&
                 // 12.1.3 并且返回值类型是基本类型
                 returnType.isPrimitive()) {
            // 12.2 抛出异常
            throw new AopInvocationException(
                "Null return value from advice does not match primitive return type for: " + method);
        }
        // 13. 返回结果
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            // 替换oldProxy
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
getInterceptorsAndDynamicInterceptionAdvice()

JdkDynamicAopProxy.invoke() 方法中的 7 中。

该方法是用于获取匹配当前方法的Advisor中的拦截器链列表,用于拦截当前方法并进行增强。

因为此前设置到 proxyFactory 中的 advisors 集合中的 Advisor ,只能说是匹配当前方法所属的类以及类中的某些方法,但并不一定匹配当前的方法,比如expression不匹配。所以需要重新根据方法来获取对应拦截器列表。

获取到的拦截器列表将会存到 methodCache 缓存中(位于父类 AdvisedSupport 中),当新增Advisor的时候会清空,否则后续对于同一个方法的拦截将直接从缓存中获取拦截器链。

对于 AnnotationAwareAspectJAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator 自动代理创建者。第一个拦截器就是 ExposeInvocationInterceptor ,它是后面在 extendAdvisors() 方法中加入进去的,其规则匹配所有方法。

// 获取方法拦截器链的工厂
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
// 方法作为key,将该方法的拦截器链集合作为value的ConcurrentHashMap集合
private transient Map<MethodCacheKey, List<Object>> methodCache;

// 构造初始化methodCache
public AdvisedSupport() {
    this.methodCache = new ConcurrentHashMap<>(32);
}

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Method method, // 目标方法
    @Nullable Class<?> targetClass // 目标类
) {
    // 1. 根据当前方法生成缓存key
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    // 2. 从缓存中获取此前解析的适合给定方法的拦截器调用链列表
    List<Object> cached = this.methodCache.get(cacheKey);
    // 3. 如果没有缓存,则解析该方法
    if (cached == null) {
        // 4. 调用advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法解析
        // 默认是DefaultAdvisorChainFactory
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
        // 5. 解析结果存入methodCache缓存,下一次直接从缓存获取
        this.methodCache.put(cacheKey, cached);
    }
    // 6. 返回缓存
    return cached;
}
getInterceptorsAndDynamicInterceptionAdvice()

getInterceptorsAndDynamicInterceptionAdvice 中调用 DefaultAdvisorChainFactory 内的同名方法。

DefaultAdivsorChainFactory 会通过一个 AdvisorAdapterRegistry 来实现拦截器的注册, AdvisorAdapterRegistryadvice 通知的织入功能起了很大的作用。

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, @Nullable Class<?> targetClass) {

    // 1. 获取Advisor适配器注册表,默认获取的是一个DefaultAdvisorAdapterRegistry类型的单例
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    // 2. 从proxyFactory中获取此前设置的全部advisors
    Advisor[] advisors = config.getAdvisors();
    // 拦截器列表
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    // 实际目标类型
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    // 是否具有引介增强
    Boolean hasIntroductions = null;
	// 3. 遍历advisors集合
    for (Advisor advisor : advisors) {
        // 4. 如果属于PointcutAdvisor,即切入点通知器
        // 比如<aop:advisor />标签的DefaultBeanFactoryPointcutAdvisor
        // 以及通知标签的AspectJPointcutAdvisor,都是PointcutAdvisor类型
        if (advisor instanceof PointcutAdvisor) {
            // 4.1 类型转换
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            // 4.2 判断切入点增强器是否匹配当前方法
            if (config.isPreFiltered() ||
                pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 4.3 获取方法匹配器,比如AspectJExpressionPointcut切入点
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 4.4 AspectJExpressionPointcut属于IntroductionAwareMethodMatcher,适配引介增强
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    match = mm.matches(method, actualClass);
                }
                // 4.5 如果匹配当前方法
                if (match) {
                    // 4.6 将当前advisor通知器转换为MethodInterceptor方法拦截器
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // 4.7 是否需要动态匹配
                    // 比如expression中使用args()等可以传递参数的PCD类型,那么就需要动态匹配,可以匹配的某个参数的运行时传递的类型及其子类型
                    //动态匹配开销比较大,一般都不是也不需要使用
                    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) {
                            // 4.7.1 封装成为InterceptorAndDynamicMethodMatcher
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // 5. 如果属于IntroductionAdvisor,即引介增强通知器
        // 比如<aop:declare-parents/>标签的DeclareParentsAdvisor就是IntroductionAdvisor类型
        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));
            }
        }
        // 6. 否则,默认匹配
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}
DefaultAdvisorAdapterRegistry

getInterceptorsAndDynamicInterceptionAdviceGlobalAdvisorAdapterRegistry.getInstance() 中获取 DefaultAdvisorAdapterRegistry 单例对象。

private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();

public static AdvisorAdapterRegistry getInstance() {
    return instance;
}

DefaultAdvisorAdapterRegistry 的作用是用于使用 AdvisorAdapter 通知器适配器将通知器 Advisor 转换为拦截器 MethodInterceptor

DefaultAdvisorAdapterRegistry 可以理解为通知器适配器注册表,因此 DefaultAdvisorAdapterRegistry 本身没有转换功能,该功能是内部的通知器适配器完成的。

DefaultAdvisorAdapterRegistry 初始化的时候,就会默认注册3个通知器适配器到内部缓存adapters中,分别是:

  • MethodBeforeAdviceAdapter
  • AfterReturningAdviceAdapter
  • ThrowsAdviceAdapter
public DefaultAdvisorAdapterRegistry() {
    // 注册MethodBeforeAdvice类型的通知器的配置器,常见通知器实现就是AspectJMethodBeforeAdvice
    // 也就是转换前置通知器,<aop:before/>通知
    registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
    // 注册AfterReturningAdvice类型的通知器的配置器,常见通知器实现就是AspectJAfterReturningAdvice
    // 也就是转换后置通知器,<aop:after-returning/>通知
    registerAdvisorAdapter(new AfterReturningAdviceAdapter());
    // 注册ThrowsAdvice类型的通知器的适配器,没有常见通知器实现
    registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

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

通过调用 getInterceptors 来获取拦截器。

通过给定的通知器获取对应的拦截器。

不同的通知器的对应关系如下:

通知标签对应类对应类的实现接口
<aop:before />AspectJMethodBeforeAdviceMethodBeforeAdvice
<aop:after />AspectJAfterAdviceMethodInterceptor
<aop:after-returning />AspectJAfterReturningAdviceAfterReturningAdvice
<aop:after-throwing />AspectJAfterThrowingAdviceMethodInterceptor
<aop:around />AspectJAroundAdviceMethodInterceptor
@Override
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);
    }
    // 否则尝试通过适配器转换
    for (AdvisorAdapter adapter : this.adapters) {
        // 如果该是配置支持当前通知
        if (adapter.supportsAdvice(advice)) {
            // 适配转换成MethodInterceptor并添加到当前通知
            interceptors.add(adapter.getInterceptor(advisor));
        }
    }
    // 如果为空集合,抛出异常
    if (interceptors.isEmpty()) {
        throw new UnknownAdviceTypeException(advisor.getAdvice());
    }
    return interceptors.toArray(new MethodInterceptor[0]);
}
new ReflectiveMethodInvocation(…)

JdkDynamicAopProxy.invoke() 方法中的 9.1 中。

创建一个 MethodInvocation 方法调用服务,参数为代理对象目标对象方法参数目标类型该方法的拦截器链集合。这个对象主要就是用来进行方法调用和增强。

protected ReflectiveMethodInvocation(
    Object proxy, // 调用的代理对象
    @Nullable Object target, // 要调用的目标对象
    Method method, // 调用的方法
    @Nullable Object[] arguments, // 调用方法的参数
    @Nullable Class<?> targetClass, // 目标类,用于MethodMatcher调用
    List<Object> interceptorsAndDynamicMethodMatchers // 需要应用的拦截器链集合
) {
    this.proxy = proxy;
    this.target = target;
    this.targetClass = targetClass;
    this.method = BridgeMethodResolver.findBridgedMethod(method);
    this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
    this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
proceed()

JdkDynamicAopProxy.invoke() 方法中的 9.1 中。

这里使用了责任链模式的设计思想,按顺序递归的执行拦截器链中拦截器的 invoke() 方法以及目标方法。invoke() 方法中就会执行对目标方法前后或者抛出异常时的增强(通知)的逻辑。

该方法实现递归的逻辑在于两点:

  • currentInterceptorIndex 索引属性
    • currentInterceptorIndex 属性在每一次调用 proceed() 方法时都会自增1,这样每一次执行 proceed() 方法时都会获取下一个拦截器。
  • invoke() 方法
    • invoke() 方法中递归调用 proceed() 方法。

this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1 判断为true,即最后一个拦截器已经调用完成,则会执行 invokeJoinpoint() 方法,这个就是反射执行被代理的方法,也就是原始方法的逻辑,该方法执行完毕后递归开始返回。随即执行后置通知和异常通知的逻辑,这两种通知执行完毕,最后会执行最终通知的逻辑,最终通知是在 finally 块中调用的,所以会最后执行。

// 构造中传入的拦截器链
protected final List<?> interceptorsAndDynamicMethodMatchers;
// 调用当前拦截器索引从-1开始
private int currentInterceptorIndex = -1;

@Override
@Nullable
public Object proceed() throws Throwable {
    // 判断最后一个拦截器是否调用完毕,这里的currentInterceptorIndex是从-1开始的,因此集合size需要减去1
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 如果拦截器调用完毕,那么反射执行被代理的方法,也就是原始方法
        return invokeJoinpoint();
    }
	
    // 获取下一个要调用的拦截器,currentInterceptorIndex从-1开始,先自增再获取值
    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // 如果是需要动态检查的拦截器
    // 比如具有args()、@annotation()等动态参数的PCD,需要动态的分析方法参数等信息,性能较低,一般都是走下面的逻辑
    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 {
            // 动态匹配失败,跳过此拦截器并调用链中的下一个拦截器
            return proceed();
        }
    }
    // 如果是普通的拦截器,大部分拦截器都是普通拦截器
    else {
        // 调用拦截器自己的invoke方法,这个invoke方法中就有在目标方法前后的后增强的逻辑
         // 这个this指的是当前的ReflectiveMethodInvocation对象
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

invokeJoinpoint 方法是通过反射调用目标方法(被代理的方法),参数为目标对象(被代理原始对象)传递的方法参数

当这个方法执行结束后,递归开始返回。

@Nullable
protected Object invokeJoinpoint() throws Throwable {
    return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

@Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
    throws Throwable {

    // Use reflection to invoke the method.
    try {
        // 设置方法的可访问属性即method.setAccessible(true)
        ReflectionUtils.makeAccessible(method);
        // 反射调用目标对象的原始方法并获取返回值
        return method.invoke(target, args);
    }
    catch (InvocationTargetException ex) {
        throw ex.getTargetException();
    }
    catch (IllegalArgumentException ex) {
        throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                                         method + "] on target [" + target + "]", ex);
    }
    catch (IllegalAccessException ex) {
        throw new AopInvocationException("Could not access method [" + method + "]", ex);
    }
}

下面举例几种常见的 MethodInterceptorinvoke() 方法。

ExposeInvocationInterceptor.invoke()

前面说过 AnnotationAwareAspectJAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator 自动代理创建者,第一个拦截器就是ExposeInvocationInterceptor。它是通过 extendAdvisors() 扩展方法加入进去的。

该拦截器不属于通知方法的拦截器,主要目的是将当前MethodInvocation,也就是ReflectiveMethodInvocation对象设置到线程本地变量属性invocation中(暴露当前MethodInvocation),方便后续拦截器可以快速获取。

// ThreadLocal对象,保存ReflectiveMethodInvocation对象,方便后面通过静态方法获取
private static final ThreadLocal<MethodInvocation> invocation =
			new NamedThreadLocal<>("Current AOP method invocation");

@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    // 将当前MethodInvocation设置到线程本地变量中
    invocation.set(mi);
    try {
        // 继续调用mi.proceed(),这里出现递归调用的逻辑了
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}
MethodBeforeAdviceInterceptor.invoke()

它是 前置通知拦截器,方法逻辑比较简单,先调用 before()方法,再调用 proceed() 继续递归。

before() 方法用于调用前置通知,其内部最终会调用 invokeAdviceMethodWithGivenArgs 方法反射执行通知方法,这个方法也是通用的通知的执行方法,在 AbstractAspectJAdvice 中实现。

before() 方法首先调用的是 invokeAdviceMethod() 方法,其中传参调用了 getJoinPointMatch() 方法。

该方法用于在我们被调度的连接点获取当前连接点匹配。

@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
    // 通过当前通知实例调用前置通知方法,此时目标方法未被执行
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    // 继续递归调用proceed()
    return mi.proceed();
}

@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
    // 内部调用的invokeAdviceMethod方法
    invokeAdviceMethod(getJoinPointMatch(), null, null);
}

// -------------------------------------------

// AbstractAspectJAdvice 656
/*
	getJoinPointMatch用于获取当前连接点匹配结果,用于通知方法的参数匹配和传递,一般都是null
	如果expression中配置了args()的PCD并且需要通知方法需要传递参数,那么JoinPointMatch不为null
    如果有其他能够传参的PCD,那么jpMatch也不会为null,比如@annotation()的PCD就能传递方法上的注解作为参数
*/
@Nullable
protected JoinPointMatch getJoinPointMatch() {
    MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    // 通过 ThreadLocal 缓存中获取 ProxyMethodInvocation 对象
    return getJoinPointMatch((ProxyMethodInvocation) mi);
}
@Nullable
protected JoinPointMatch getJoinPointMatch(ProxyMethodInvocation pmi) {
    // 获取expression表达式
    String expression = this.pointcut.getExpression();
    return (expression != null ? (JoinPointMatch) pmi.getUserAttribute(expression) : null);
}

继续看 before() 方法调用 invokeAdviceMethod() 方法,其中传参调用了 getJoinPoint() 方法和 argBinding() 方法。

getJoinPoint() 用于懒加载 JoinPoint,封装 MethodInvocationProceedingJoinPoint 保存当前的 ReflectiveMethodInvocation 引用到参数名为 JOIN_POINT_KEY 的缓存中。

argBinding() 用于确定通知方法的参数,在调用 invokeAdviceMethodWithGivenArgs 之前,会调用 argBinding() 获取该通知方法需要传递的参数数组。对于 JoinPoint 连接点参数、普通参数、目标方法返回值以及抛出的异常这四种参数的封装都是该方法完成的,这是一个通用方法,所有类型的通知都会调用该方法。

// AbstractAspectJAdvice 613
protected Object invokeAdviceMethod(
    @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
    throws Throwable {

    return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

// ------------------------------------------------

// 获取当前方法连接点
protected JoinPoint getJoinPoint() {
    return currentJoinPoint();
}

// 当前连接点用于userAttributes缓存map中的key,即 org.aspectj.lang.JoinPoint
protected static final String JOIN_POINT_KEY = JoinPoint.class.getName();

public static JoinPoint currentJoinPoint() {
    // 从ThreadLocal中获取ReflectiveMethodInvocation
    MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    // 类型转换
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    // 获取org.aspectj.lang.JoinPoint名称的属性值
    JoinPoint jp = (JoinPoint) pmi.getUserAttribute(JOIN_POINT_KEY);
    // 如果为null,则进行初始化,懒加载
    if (jp == null) {
        // 新建一个MethodInvocationProceedingJoinPoint,内部持有当前的ReflectiveMethodInvocation对象
        jp = new MethodInvocationProceedingJoinPoint(pmi);
        // 当前连接点设置到userAttributes缓存中,key固定为"org.aspectj.lang.JoinPoint"
        // 当后面的通知方法被回调而需要获取连接点时,直接从缓存中获取
        pmi.setUserAttribute(JOIN_POINT_KEY, jp);
    }
    return jp;
}

protected Object[] argBinding(
    // 当前方法连接点,一般用于传递到通知方法的第一个参数。用于通知方法的第一个连接点参数传递
    // 可以使用的类型为JoinPoint、ProceedingJoinPoint(环绕通知专用)、JoinPoint.StaticPart
    JoinPoint jp,
    // 匹配此执行连接点的JoinPointMatch,用于通知方法的其他普通参数的匹配和传递,一般为null
    // 如果有expression中配置了args()的PCD并且需要通知方法需要传递普通参数或者其他能够传参的PCD,则不为null
    @Nullable JoinPointMatch jpMatch,
    // 方法执行的返回值(一般都是目标方法的返回值,可能为null)。用于通知方法的方法执行返回值参数传递。
    @Nullable Object returnValue,
    // 方法执行引发的异常(一般都是目标方法抛出的异常,可能为null)。用于通知方法的方法执行异常参数传递。
    @Nullable Throwable ex
) {
    
	// 1. 优化操作,方便后面的通知的参数绑定更快的完成,具体的优化细节比较容易
    /*
    	1. 根据第一个参数的类型为JoinPoint或ProceedingJoinPoint来设置joinPointArgumentIndex或joinPointStaticPartArgumentIndex的属性值为0
    	2. 剩余参数根据argumentNames数组中的参数名以及起始索引设置argumentBinding缓存
    */
    calculateArgumentBindings();

    // 绑定的参数数组
    Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
    // 绑定的个数
    int numBound = 0;

    // 2. 绑定第一个参数
    // 2.1 如果joinPointArgumentIndex值不为-1(通过calculateArgumentBindings方法可以设置为0)
    // 那么第一参数就是JoinPoint
    if (this.joinPointArgumentIndex != -1) {
        adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
        numBound++;
    }
    // 2.2 如果joinPointStaticPartArgumentIndex值不为-1(通过calculateArgumentBindings方法可以设置为0)
    // 那么第一参数就是JoinPoint.StaticPart
    else if (this.joinPointStaticPartArgumentIndex != -1) {
        adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
        numBound++;
    }

    // 操作argumentBindings,确定具体传递的参数
    if (!CollectionUtils.isEmpty(this.argumentBindings)) {
        /*
        从切入点匹配绑定,对于普通参数或者其他参数(比如方法的注解)传递,我们需要在execution中配置传参的PCD
        比如args()、@annotation(),对于普通参数,这些PCD里面的参数位置就是对应着目标方法的参数位置
        PointcutParameter[]就是对应着位置进行封装: 【参数名,传递的参数值】
        这些PCD中设置的参数名最好和通知方法的参数名一致,如果不一致,那么需要手动配置arg-names属性等于这个参数名
        */
        if (jpMatch != null) {
            // 获取PointcutParameter数组,PointcutParameter就是【参数名,传递的参数值】
            PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
            // 遍历数组
            for (PointcutParameter parameter : parameterBindings) {
                // 获取name
                String name = parameter.getName();
                // 获取对应参数的索引
                Integer index = this.argumentBindings.get(name);
                // 在给定索引位置设置参数值
                adviceInvocationArgs[index] = parameter.getBinding();
                numBound++;
            }
        }
        // 绑定返回值参数
        if (this.returningName != null) {
            Integer index = this.argumentBindings.get(this.returningName);
            adviceInvocationArgs[index] = returnValue;
            numBound++;
        }
        // 绑定异常值参数
        if (this.throwingName != null) {
            Integer index = this.argumentBindings.get(this.throwingName);
            adviceInvocationArgs[index] = ex;
            numBound++;
        }
    }

    if (numBound != this.parameterTypes.length) {
        throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
                                        " arguments, but only bound " + numBound + " (JoinPointMatch " +
                                        (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
    }

    return adviceInvocationArgs;
}

再继续看 invokeAdviceMethodWithGivenArgs 方法,在确定需要传递的参数之后,执行该方法,根据传递的参数反射调用切面类对象的通知方法并获取返回值,也就是执行增强的逻辑。

// AbstractAspectJAdvice 627
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    // 如果通知方法参数个数为0
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        //参数数组为null
        actualArgs = null;
    }
    try {
        // 设置方法的可访问属性,即 aspectJAdviceMethod.setAccessible(true),同前面
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        // 反射调用切面类对象的通知方法并返回结果
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    }
    catch (IllegalArgumentException ex) {
        throw new AopInvocationException("Mismatch on arguments to advice method [" +
                                         this.aspectJAdviceMethod + "]; pointcut expression [" +
                                         this.pointcut.getPointcutExpression() + "]", ex);
    }
    catch (InvocationTargetException ex) {
        throw ex.getTargetException();
    }
}
AfterReturningAdviceInterceptor.invoke()

它是 后置通知拦截器,方法逻辑比较简单,先调用 proceed()方法且没有异常,再调用 afterReturning() 方法。

// 后置通知
private final AfterReturningAdvice advice;

@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
    // 继续调用proceed()方法,也是递归调用
    Object retVal = mi.proceed();
    // 目标方法执行完毕,且没有异常的情况下,执行后置通知方法
    this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
    return retVal;
}

看一下在 AfterReturningAdvice 实现的 afterReturning 方法,其内部也是通过调用 invokeAdviceMethod 方法,执行逻辑基本与前者相同。

afterReturning 方法中同时还调用了 shouldInvokeOnReturnValueOf 方法,该方法会校验返回值类型当前通知方法参数需要的返回值类型是否匹配,如果匹配那么可以调用当前后置通知方法,否则不会调用。

@Override
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
    if (shouldInvokeOnReturnValueOf(method, returnValue)) {
        invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
    }
}


private Class<?> discoveredReturningType = Object.class;
// 与返回类型类似,抛出类型不需要此类通用信息,因为Java不允许对异常类型进行参数化。
private Type discoveredReturningGenericType;

private boolean shouldInvokeOnReturnValueOf(Method method, @Nullable Object returnValue) {
    Class<?> type = getDiscoveredReturningType();
    Type genericType = getDiscoveredReturningGenericType();
    // If we aren't dealing with a raw type, check if generic parameters are assignable.
    return (matchesReturnValue(type, method, returnValue) &&
            (genericType == null || genericType == type ||
             TypeUtils.isAssignable(genericType, method.getGenericReturnType())));
}
AspectJAfterThrowingAdvice.invoke()

它是 异常通知,自身实现了 MethodInterceptor 接口,则不需要被适配成为方法拦截器。

它的 invoke() 方法逻辑比较简单,使用 try-catch 语句块,在 try 中执行 proceed() 方法,在 catch 中执行 invokeAdviceMethod 方法,在目标方法执行抛出异常的情况下,会将异常捕获,根据异常类型可能会执行异常通知。即在目标方法调用抛出异常之后才调用异常通知方法

在执行异常通知之前还会调用 shouldInvokeOnThrowing 方法,该方法会校验抛出的异常类型当前通知方法参数需要的异常类型是否匹配,如果匹配那么可以调用当前异常通知方法,否则不会调用。

@SuppressWarnings("serial")
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
    implements MethodInterceptor, AfterAdvice, Serializable {

    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        catch (Throwable ex) {
            if (shouldInvokeOnThrowing(ex)) {
                invokeAdviceMethod(getJoinPointMatch(), null, ex);
            }
            throw ex;
        }
    }

}


private boolean shouldInvokeOnThrowing(Throwable ex) {
    return getDiscoveredThrowingType().isAssignableFrom(ex.getClass());
}
AspectJAfterAdvice.invoke()

它是 最终通知,自身实现了 MethodInterceptor 接口,则不需要被适配成为方法拦截器。

它的 invoke() 方法逻辑比较简单,使用 try-finally 语句块,在 try 中执行 proceed() 方法,在 finally 中执行 invokeAdviceMethod 方法,在目标方法不管是执行成功还是抛出异常的情况下,都会执行最终通知,即在 finally 中执行 invokeAdviceMethod 方法。

@SuppressWarnings("serial")
public class AspectJAfterAdvice extends AbstractAspectJAdvice
    implements MethodInterceptor, AfterAdvice, Serializable {

    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        finally {
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }
    
}
AspectJAroundAdvice.invoke()

它是 环绕通知,自身实现了 MethodInterceptor 接口,则不需要被适配成为方法拦截器。

它的 invoke() 方法第一眼看比较特殊,因为它没有调用 mi.proceed() 方法,而是使用 ProceedingJoinPoint 封装 ProxyMethodInvocationMethodInvocationProceedingJoinPoint 重写 proceed() 方法,调用了 methodInvocationproceed() 方法,回到了递归调用逻辑。

@SuppressWarnings("serial")
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {

    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
        JoinPointMatch jpm = getJoinPointMatch(pmi);
        return invokeAdviceMethod(pjp, jpm, null, null);
    }

    protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
        return new MethodInvocationProceedingJoinPoint(rmi);
    }

}

// -------------------------- MethodInvocationProceedingJoinPoint ----------------------------
public MethodInvocationProceedingJoinPoint(ProxyMethodInvocation methodInvocation) {
    Assert.notNull(methodInvocation, "MethodInvocation must not be null");
    this.methodInvocation = methodInvocation;
}

@Override
@Nullable
public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

@Override
@Nullable
public Object proceed(Object[] arguments) throws Throwable {
    Assert.notNull(arguments, "Argument array passed to proceed cannot be null");
    if (arguments.length != this.methodInvocation.getArguments().length) {
        throw new IllegalArgumentException(
            "Expecting " +
            this.methodInvocation.getArguments().length + " arguments to proceed, " +
            "but was passed " + arguments.length + " arguments");
    }
    this.methodInvocation.setArguments(arguments);
    return this.methodInvocation.invocableClone(arguments).proceed();
}

CGLIB动态代理调用

前面我们在创建 CGLIB动态代理 对象时,创建了 ObjenesisCglibAopProxy 对象,它实现了 CglibAopProxy ,其中的 getProxy() 方法中,调用 getCallbacks() 返回回调拦截器链数组

Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

// 回调拦截器组
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)
};

所以从 DynamicAdvisedInterceptorintercept 方法开始看:

@Override
@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 targetSource = this.advised.getTargetSource();
    try {
        // 如果是需要暴露代理的对象
        if (this.advised.exposeProxy) {
            // 通过setCurrentProxy()设置到Threadlocal中,后面可以通过静态方法获取
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 获取原始目标对象,即被代理的对象
        target = targetSource.getTarget();
        // 获取原始目标对象的class
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 获取匹配当前方法的Advisor中的拦截器链列表,用于拦截当前方法并进行增强,同上文
        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 {
            // 创建CglibMethodInvocation,CglibMethodInvocation继承了ReflectiveMethodInvocation
            // CglibMethodInvocation是CglibAopProxy的内部类
            // 调用proceed方法,进行方法的代理和增强
            retVal = new CglibMethodInvocation(
                proxy, target, method, args,
                targetClass, chain, methodProxy).proceed();
        }
        // 如果有可能,将返回值替换为代理对象本身
        retVal = processReturnType(proxy, target, method, retVal);
        // 返回返回值
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
new CglibMethodInvocation(…)

核心方法就是通过创建 CglibMethodInvocation ,调用 proceed() 方法,进行方法的代理和增强。内部实际还是 ReflectiveMethodInvocation 的调用逻辑。

private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

    @Nullable
    private final MethodProxy methodProxy;

    public CglibMethodInvocation(
        Object proxy, @Nullable Object target, Method method,
        Object[] arguments, @Nullable Class<?> targetClass,
        List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy
    ) {
        super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);

        this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
                            method.getDeclaringClass() != Object.class &&
                            !AopUtils.isEqualsMethod(method) &&
                            !AopUtils.isHashCodeMethod(method) &&
                            !AopUtils.isToStringMethod(method)
                            ?
                            methodProxy : null);
    }

    @Override
    @Nullable
    public Object proceed() throws Throwable {
        try {
            return super.proceed();
        }
        catch (RuntimeException ex) {
            throw ex;
        }
        catch (Exception ex) {
            if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
                KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
                throw ex;
            }
            else {
                throw new UndeclaredThrowableException(ex);
            }
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

舍其小伙伴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值