Spring中AOP及ReflectiveMethodInvocation逻辑简析

本文深入解析了Spring AOP的工作原理,包括Advisor的生成、AOP代理的创建、JdkDynamicAopProxy的invoke方法以及ReflectiveMethodInvocation的proceed过程。内容涵盖了AspectJ、SpringAOP的两种代理方式、AOP术语解释以及AdvisedSupport在生成拦截器链中的作用。文章通过具体代码分析了AOP执行的四个步骤,展示了如何从Advisor实例到最终的拦截器调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文参考:
SpringFramework中ReflectiveMethodInvocation有什么用
DynamicAdvisedInterceptor原理
SpringAop之AdvisedSupport
从 AbstractPointcutAdvisor 开始: Spring AOP 之 Advisor、PointcutAdvisor 介绍

AOP简述

为了能够更好地将系统级别的代码抽离出来,去掉与对象的耦合,就产生了面向AOP(面向切面)。AOP全称 Aspect-Oriented
Programming , 即面向切面编程。

  • AspectJ
    AspectJ是一个基于Java语言的AOP框架,它采用编译时增强,会将增强目标编译得到一个新的AOP代理类。
    Spring AOP Spring提供的AOP框架,使用了和AspectJ一样的注解,但是通过动态生成代理类的方式生成AOP代理类。

  • JDK Dynamic AOP Spring
    AOP中AOP代理的一种实现,使用原生JDK反射和动态代理生成AOP代理,需要代理类与目标实现相同的接口。

  • CGLib AOP
    Spring AOP中AOP代理的另一种实现,使用CGLib动态生成AOP代理类,需要代理类为目标类的子类。

AOP术语 Aspect 一个切面,可以理解为一个切面模块,将相关的增强内容写进同一个切面。例如:一个负责日志的切面。

  • Join Point 代表可以由AOP增强织入的程序执行节点。

  • Advice 所要做的增强处理

  • Pointcut 切入点,定义了将被Advice增强的一个或多个Join Point,可以使用正则表达式或模式匹配。

  • Target object 被增强的目标对象

  • Adivce的种类:Before 方法执行之前; After 方法执行之后;After-returning 方法成功执行完成之后; After-throwing 方法抛出异常之后;Around 环绕方法执行的整个周期

Spring执行AOP的过程

从代码执行角度来看,Spring AOP的执行过程分为四大步骤:

步骤一:Spring框架生成Advisor实例,可以是@Aspect,@Async等注解生成的实例,也可以是程序员自定义的AbstractAdvisor子类的实例。

步骤二:Spring框架在目标实例初始化完成后,也就是使用BeanPostProcessor的postProcessAfterInitialization方法,根据Advisor实例中切入点Pointcut的定义,选择出适合该目标对象的Advisor实例。

步骤三:Spring框架根据Advisor实例生成代理对象。

步骤四:调用方法执行过程时,Spring 框架执行Advisor实例的通知Advice逻辑。

Spring中有大量的机制都是通过AOP实现的,比如说@Async的异步调用和@Transational。此外,用户也可以使用@Aspect注解定义切面或者直接继承AbstractPointcutAdvisor来提供切面逻辑。上述这些情况下,AOP都会生成对应的Advisor实例。

AdvisedSupport

在代理方法执行时,需要调用JdkDynamicAopProxy实例,其中,有一个成员变量是AdvisedSupport

    private final AdvisedSupport advised;

AdvisedSupport的类图如下:
在这里插入图片描述

AdvisedSupport继承ProxyConfig,主要有如下方法:

  • 配置当前代理的Advisor(private List advisors)
  • 配置当前代理的接口(private List<Class<?>> interfaces)
  • 配置当前代理的目标对象(TargetSource targetSource)
  • 提供getInterceptorsAndDynamicInterceptionAdvice方法用来获取对应代理方法对应有效的拦截器链
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
        AdvisedSupport.MethodCacheKey cacheKey = new AdvisedSupport.MethodCacheKey(method);
        List<Object> cached = (List)this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }

        return cached;
    }

这个方法对需要获取的拦截器链做了缓存,先取缓存,如果取不到,再调DefaultAdvisorChainFactory来执行实际的逻辑
DefaultAdvisorChainFactory中该方法如下,主要逻辑:

  1. 获取所有配置的advisors
  2. 遍历advisors数组,根据advisor是不同的类型走不同的逻辑,最终调用registry.getInterceptors转化成Interceptor返回

AdvisedSupport是用来生成拦截器chain的

IntroductionAdvisor与PointcutAdvisor都继承自Advisor,他们最本质上的区别就是,IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice。而不能像PointcutAdvisor那样,可以使用任何类型的Pointcut,以及几乎任何类型的Advice。

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

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				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) {
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(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));
			}
		}

		return interceptorList;
	}

JdkDynamicAopProxy的invoke

简单介绍一下ReflectiveMethodInvocation

ReflectiveMethodInvocation是AOP中一个重要的类,这个类在JdkDynamicAopProxy的invoke方法中使用到,可以看到在方法中,用拦截器链,代理的目标对象等参数,生成ReflectiveMethodInvocation实例

其中invoke方法主要逻辑是:

  1. 获取拦截器
  2. 如果拦截器为空,直接反射调用
  3. 如果不为空,创建ReflectiveMethodInvocation类,调用起proceed方法
// JdkDynamicAopProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       ...       
       // 得到所有作用在该方法上的拦截器和通知:创建代理的时候,只要切入点匹配了原始类的任意一个方法,原始对象都会被包装。而真正调用的时候,有些方法是不需要增强的,不需要的直接反射调用,需要的方法才走增强调用,所以拦截器通知需要过滤。
       List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
       // chain为空,直接反射调用;不为空创建一个CglibMethodInvocation对象,并调用proceed方法
       if (chain.isEmpty()) {
           Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
           retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
       } else {
           MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
           retVal = invocation.proceed();
       }
       // 如果方法返回值是原始对象,则返回代理对象,如果不是,则返回值
       ...
}

ReflectiveMethodInvocation的proceed

proceed方法的主要逻辑是:

  1. 查看是否访问到最后一个拦截器,如果是,调用invokeJoinpoint
  2. 如果还有拦截器,则看是否匹配,匹配的话调用拦截器的invoke,否则递归
  3. 如果不匹配,则直接调用该拦截器
// ReflectiveMethodInvocation 中
@Nullable
public Object proceed() throws Throwable {
    // currentInterceptorIndex表示访问到第几个拦截器,如果是最后一个,那么调用invokeJoinpoint(), 利用反射方式调用目标方法
    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();
            // 如果匹配则invoke,否则proceed递归
            return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
        } else {
            // 是拦截器,调用该拦截器
            return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

小结

  1. Spring框架启动时根据注解等配置,生成Advisor实例和代理对象
  2. 方法执行时,JdkDynamicAopProxy中获取Advisor数组,遍历得到拦截器链
  3. 拦截器链不为空,创建ReflectiveMethodInvocation类,调用起proceed方法
  4. proceed方法中递归调用下一个拦截器链,或执行目标方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值