Spring AOP 执行原理

53 阅读4分钟

代理创建

Spring AOP 实现主要依赖于 AbstractAutoProxyCreator类的执行,该类会在 Bean 的创建过程中判断是否需要生成代理对象,并获取 BeanFactory 中的可应用到当前 Bean 的增强通知 Advice。当目标对象 Bean 方法执行时通过动态代理执行时则会执行对应的增强通知方法,最终实现 AOP 切面增强的能力。

下面是 AbstractAutoProxyCreator创建过程

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

        ...
        //通过ProxyFactory创建目标对象 
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

        ...
        // 构建增强通知
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

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

		return proxyFactory.getProxy(getProxyClassLoader());
	}

查看 ProxyFactory 的创建代理对象过程

	public Object getProxy(@Nullable ClassLoader classLoader) {
        // 生成 AopProxy 实例,创建代理对象
		return createAopProxy().getProxy(classLoader);
	}
    protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
        // 获取代理创建工厂类并根据代理配置创建 AopProxy 实例
        // 默认采用 DefaultAopProxyFactory 类
		return getAopProxyFactory().createAopProxy(this);
	}

Spring AOP 支持 JDK 动态代理 与 CGLIB 动态代理两种方式,提供了 JdkDynamicAopProxy 与 ObjenesisCglibAopProxy 两种 AOP 动态代理实现类。JDK 仅支持接口的动态代理,而 CGLIB 支持目标类的代理模式,Spring 默认采用了 JDK 动态代理方式。

查看下 DefaultAopProxyFactory 创建 AopProxy过程

	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 优先使用 JDK动态代理
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

JdkDynamicAopProxy 是 Spring AOP 用于创建基于 JDK 动态代理的 AOP 代理对象的核心类。它实现了 AopProxy 与 InvocationHandler 接口,并使用 Java 的 InvocationHandler 来拦截方法调用,最终完成切面增强逻辑。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    ...
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
	}
    ...
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ...
    }
}

java 动态代理通过两个核心类实现:

  • 1.Proxy 类提供了创建代理对象的方法。
  • 2.InvocationHandler 接口定义了代理对象在方法调用时的行为,必须实现该接口并重写 invoke 方法。

在代理对象执行时会执行 InvocationHandler 实现类的 invoke 方法,在 invoke 方法中可以添加自定义逻辑,实现动态增强逻辑。

AOP 执行

JdkDynamicAopProxy通过 getProxy 获取目标实例 Bean 动态代理对象,在代理对象执行时则会调用 invoke方法,并在该方法逻辑中实现增强逻辑。下面为JdkDynamicAopProxy#invoke源码

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
            // 判断是否为 equals 或者 hashCode 方法
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;
            
			if (this.advised.exposeProxy) {
				// 暴露代理对象,将当前代理对象放置到 ThreadLocal 中
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// 针对不同类型的 TargetSoruce 获取目标对象
            // 比如 SingletonTargetSource 获取单例目标对象,也是最常见类型
            // ThreadLocalTargetSource 获取 ThreadLocal 中的目标对象
            // CommonsPool2TargetSource 支持从对象池中获取目标对象
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// 构建通知增强拦截器链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// 不存在拦截器则直接执行
			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();
			}

			// 方法返回
			Class<?> returnType = method.getReturnType();
            ...
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// 释放目标对象,比如PoolTargetSource 池化类型需要进行释放
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// 恢复旧代理对象
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

源码解释:

  • 判断方法是否为 equals 或 hashCode 等特殊类型方法,以决定是否直接调用目标对象的方法
  • 判断配置是否可以代理暴露,然后将其设置到 ThreadLocal 线程变量中
    • 通过指定 EnableAspectJAutoProxy(exposeProxy=true) 注解,在程序中通过 AopContext.currentProxy()方法即可获取当前线程变量中的代理对象
  • 通过 TargetSource 实例获取目标对象
    • TargetSource 主要作用提供代理对象使用的目标对象,并在允许在代理过程中动态切换目标,比如 CommonsPool2TargetSource 可以从对象池获取目标对象,ThreadLocalTargetSource可以通过 ThreadLocal 获取目标对象
  • 构建应用于目标方法拦截器链,比如前置通知、环绕通知、后置通知方法拦截器
  • 构建执行上下文对象 ReflectiveMethodInvocation并调用 proceed方法,递归执行拦截器逻辑
  • 完成代理增强返回结果

ReflectiveMethodInvocation

ReflectiveMethodInvocation表示目标方法的执行上下文,比如目标实例、方法与方法参数和方法拦截器链,用于目标方法的调用并执行增强拦截器。

proceed 方法源码如下

	public Object proceed() throws Throwable {
		// 当拦截器链执行到最后时调用目标方法
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
        // 获取下一个拦截器并增加拦截器索引
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		// 判断是动态拦截器还是普通拦截器
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // interceptorOrInterceptionAdvice 可实现参数匹配动态拦截匹配
			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 {
			// 执行方法拦截器
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}
    protected Object invokeJoinpoint() throws Throwable {
        return AopUtils.invokeJoinpointUsingReflection(target, method, arguments);
    }

该方法核心逻辑即递归调用拦截器链中的下一个拦截器,每个方法拦截器在执行时都需要回调ReflectiveMethodInvocation 的 proceed 方法完成链式调用,直到所有拦截器都执行完毕或到达目标方法。