揭秘AnnotationAwareAspectJAutoProxyCreator:Spring AOP自动代理的幕后英雄

概述

AnnotationAwareAspectJAutoProxyCreator 是 Spring 框架中一个用于支持面向切面编程(AOP)的组件。它主要用于自动检测和处理使用注解定义的切面,从而在 Spring 应用程序上下文中创建 AOP 代理。

AnnotationAwareAspectJAutoProxyCreator 继承自 AspectJAwareAdvisorAutoProxyCreator,是一个具体的 BeanPostProcessor 实现。它主要负责:

  1. 在 Spring 应用上下文中查找所有切面(通常是使用 @Aspect 注解标记的类)。
  2. 为这些切面创建代理对象。
  3. 将代理对象注册到 Spring 应用上下文中,以便在运行时能够正确地拦截和处理方法调用。

AnnotationAwareAspectJAutoProxyCreator 的主要作用包括:

  1. 自动代理创建:自动为 Spring 应用上下文中的符合条件的 Bean 创建代理,无需手动配置代理。
  2. 注解处理:专门处理基于注解的 Aspect 切面定义(如 @Aspect),简化了 AOP 的配置和使用。
  3. 方法拦截:在方法执行前后或抛出异常时,执行切面中定义的通知方法(如 @Before、@After、@AfterReturning、@AfterThrowing 和 @Around)。
  4. 增强功能:通过面向切面编程,实现横切关注点(如事务管理、日志记录、安全检查等)的分离和模块化。

类结构分析

AnnotationAwareAspectJAutoProxyCreator 的类图如下:

查看继承关系可以发现,此类实现了 Aware 与 BeanPostProcessor 接口,这两个接口都和 Spring Bean 的初始化有关,由此推测此类主要处理方法都来自这两个接口的实现方法。同时该类也实现了 Ordered 方法。

AbstractAutoProxyCreator

在 AnnotationAwareAspectJAutoProxyCreator 类的继承关系上可以看出,是在 AbstractAutoProxyCreator 类开始实现 SmartInstantiationAwareBeanPostProcessor 接口和 BeanFactoryAware 接口的。AbstractAutoProxyCreator 类都是直接实现了这两个接口。

既然 AbstractAutoProxyCreator 实现了 BeanFactoryAware 接口, 那么 AbstractAutoProxyCreator 类中就一定存在 setBeanFactory() 方法,如下所示:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    // ...
      
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

	@Nullable
	protected BeanFactory getBeanFactory() {
		return this.beanFactory;
	}
    
    // ...
}

在 AbstractAutoProxyCreator 类中还存在与 BeanPostProcessor 后置处理器有关的方法,分别为:postProcessBeforeInstantiation()、postProcessAfterInstantiation()、postProcessProperties()、postProcessBeforeInitialization()、postProcessAfterInitialization()。整体源代码如下所示:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    // ...
      
	@Override
	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;
			}
			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;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
		return true;
	}

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		return pvs;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}

	/**
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
    
    // ...
}

到这,我们就在 AbstractAutoProxyCreator 类中看到了 BeanFactoryAware 的实现和 BeanPostProcessor后置处理器的实现。

AbstractAdvisorAutoProxyCreator

我们再来看看 AbstractAutoProxyCreator 的子类 AbstractAdvisorAutoProxyCreator 类。

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {

    // ...

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
			throw new IllegalArgumentException(
					"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
		}
		initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
	}
    
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    	this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
	}
    
    // ...
}

此段代码说明在 AbstractAdvisorAutoProxyCreator 类中重写了 setBeanFactory() 方法。并且在 AbstractAdvisorAutoProxyCreator 类的 setBeanFactory() 方法中,首先会调用 AbstractAutoProxyCreator 类中的 setBeanFactory() 方法。

另外,我们并没有在 AbstractAdvisorAutoProxyCreator 类中找到与后置处理器相关的方法。

AspectJAwareAdvisorAutoProxyCreator

通过查看 AspectJAwareAdvisorAutoProxyCreator 类的源码,我们得知,在 AspectJAwareAdvisorAutoProxyCreator 类中没有与后置处理器相关的代码。所以,我们继续向下分析 AspectJAwareAdvisorAutoProxyCreator 类的子类 AnnotationAwareAspectJAutoProxyCreator。

AnnotationAwareAspectJAutoProxyCreator

在 AnnotationAwareAspectJAutoProxyCreator 类中,我们可以找到一个 initBeanFactory() 方法,如下所示:

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {

     // ...
	
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
            super.initBeanFactory(beanFactory);
            if (this.aspectJAdvisorFactory == null) {
                this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
            }

            this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
        }
     // ...
    
}

看到这里,对于 setBeanFactory 的调用流程有点清晰了吧?其实 setBeanFactory() 的调用流程为:

  1. 首先会执行 AbstractAdvisorAutoProxyCreator 类中的 setBeanFactory() 方法
  2. 在 AbstractAdvisorAutoProxyCreator 类中的 setBeanFactory() 方法中会调用其父类 AbstractAutoProxyCreator 中的 setBeanFactory() 方法
  3. 然后在 AbstractAdvisorAutoProxyCreator 类中的 setBeanFactory() 方法中调用 initBeanFactory() 方法。
  4. 由于在子类 AnnotationAwareAspectJAutoProxyCreator 中重写了 initBeanFactory() 方法,最终调用的就是 AnnotationAwareAspectJAutoProxyCreator 类中的 initBeanFactory() 方法。
  5. 在 AnnotationAwareAspectJAutoProxyCreator 中首先会执行调用父类 AbstractAdvisorAutoProxyCreator 的 initBeanFactory() 方法。

初始化过程

通过查看 @EnableAspectJAutoProxy 注解的源码,如下所示:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	boolean proxyTargetClass() default false;

	boolean exposeProxy() default false;
}

@EnableAspectJAutoProxy 注解是通过使用 @Import(AspectJAutoProxyRegistrar.class) 给容器中注册一个名字叫做 internalAutoProxyCreator = AnnotationAwareAspectJAutoProxyCreator 的组件。

源码剖析

代理创建流程

创建代理的核心逻辑是在 postProcessAfterInitialization 方法中,也就是初始化完成后,通过 BeanPostProcessor 的后置处理器完成代理对象的创建。

核心代码位于 AbstractAutoProxyCreator 类中,他是 AnnotationAwareAspectJAutoProxyCreator 的父父父类。

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    // ...

	/**
	 * bean 是原始对象,beanName 是原始对象的 ID 值
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
            // 解决循环引用的问题,之前循环引用的处理也是可以提前通过 Lambda 创建代理对象的,如果之前已经创建过,则直接返回
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                // 真正创建代理的核心,判断是否需要代理并进行代理包装
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
    
    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;
		}

		// 下面这一段是创建代理的核心逻辑
        // 获取当前 Bean 的拦截器(其实就是我们的切面和额外功能)通过当前 Bean,获取能否拦截的切面
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != null) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 创建代理对象
			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;
	}
    
    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);
			}
		}

        // 为代理工厂设置额外功能
		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());
	}
    
    // ...
}

如何选择使用 JDK 动态代理或 CGLIB 动态代理?

代理工厂在创建代理对象的时候,也就对应上面代码的最后一行,这里在 createAopProxy 的时候,就会根据实际的情况来选择创建 CglibAopProxy 还是 JdkDynamicAopProxy。

public class ProxyFactory extends ProxyCreatorSupport {
    
    // ...
    
	public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}
    
    // ...
}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.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 (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            // 如果有接口,就用 JDK 动态代理
            return new JdkDynamicAopProxy(config);
        }
        // 使用 CGLIB 动态代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

总结一下代理对象的创建过程:

  1. Spring 代理对象的创建是通过 BeanPostProcessor 的后置处理器,也就是初始化后完成代理对象的创建的,具体是 AnnotationAwareAspectJAutoProxyCreator 处理。
  2. 代理对象的创建是 AnnotationAwareAspectJAutoProxyCreator 的父类 AbstractAutoProxyCreator 完成。
  3. 首先在创建代理对象的时候先考虑到了循环引用的问题,因为在发生循环引用的时候,代理对象的创建可能会提前,在处理循环引用的时候有个 Lambda 表达式也可以提前把代理对象创建出来,如果之前已经创建过了,那么直接就返回就行,不需要重新再创建。
  4. 之后获取原始对象能够匹配的拦截器(切面),如果有切面则会进行代理的创建,没有的话直接返回。
  5. 在创建代理的时候底层是交给了 ProxyFactory 来处理,再往底层会根据情况(比如是否原始对象有接口)来选择使用 JDK 还是 CGLIB。这两类动态代理底层都有一个 AopProxy 的实现类。

代理生效流程

实际上代理的生效是动态的,单纯通过源码我们是无法看出动态的效果,所以我们需要搭配 Debug 来观察。

如果我们已经为某个 Bean 配置了 AOP 的切面和额外功能,那么我们在从上下文中获取的时候获得的就是代理对象。

实际调用代理对象的方法的时候,就会执行代理的逻辑,根据策略的不同,可能是 JdkDynamicAopProxy / CglibAopProxy。

这两种代理生效的过程都非常的类似,执行的大概逻辑如下:

  1. 进行一些安全性的校验:处理代理的方法是 Object 顶级类的方法,例如 equals、hashCode 等,这些方法是不需要执行代理的逻辑的。
  2. 判断是否开启了暴露代理的配置:@EnableAspectJAutoProxy 如果配置了 proxyTargetClass = true,则将代理对象放入 ThreadLocal,以方便后续获取,解决代理对象的方法中调用本来其他方法代理失效的问题。
  3. 获取原始对象的信息
  4. 获取拦截器(额外功能)链:获取符合 AOP 配置切入点的拦截器链,同一个方法可以设置多个 AOP 切入点,多个切入点的顺序可以使用 @Ordered 注解指定,越小越优先。如何判断是否满足切入点的配置?底层是通过 Pointcut 接口的 AspectJExpressionPointcut 来进行条件的判断,先匹配类型,再匹配方法
  5. 整合原始方法和额外功能:创建 MethodInvocation 对象,将代理对象、原始对象、代理方法、参数、原始目标类、额外功能链路都统一的整合到一起。
  6. 执行上面创建的 MethodInvocation:按照顺序逐个执行拦截器链中每个拦截器的逻辑,这里面是一个链式调用。会在原始方法执行前,按照顺序调用所有前置的额外功能,在原始方法执行后,按照顺序执行所有后置的额外功能。
JDK 动态代理的生效

使用 JDK 动态代理创建的对象,当调用代理对象的代理的方法的时候,会进入 JdkDynamicAopProxy 的 invoke 方法。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    // ...

    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;
		
        // 处理代理的方法是 Object 顶级类的方法,例如 equals、hashCode 等,这些方法是不需要执行代理的逻辑的
        try {
            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) {
                // @EnableAspectJAutoProxy 如果配置了 proxyTargetClass = true
                // 则将代理对象放入 ThreadLocal,以方便后续获取,解决代理对象的方法中调用本来其他方法代理失效的问题。
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // 获取原始对象的信息
            target = targetSource.getTarget();
            Class<?> targetClass = (target != null ? target.getClass() : null);

            // 获取符合 AOP 配置切入点的拦截器链,同一个方法可以设置多个 AOP 切入点,多个切入点的顺序可以使用 @Ordered 注解指定,越小越优先
            // 如何判断是否满足切入点的配置?底层是通过 Pointcut 接口的 AspectJExpressionPointcut 来进行条件的判断,先匹配类型,再匹配方法
            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();
            if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                retVal = proxy;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
    // ...
}
CGLib 动态代理的生效

使用 CGLib 动态代理创建的对象,当调用代理对象的代理的方法的时候,会进入 CglibAopProxy 的内部拦截器类 DynamicAdvisedInterceptor 的 intercept 方法。

class CglibAopProxy implements AopProxy, Serializable {

    // ...

    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

        // ...

        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();
            try {
                if (this.advised.exposeProxy) {
                    // @EnableAspectJAutoProxy 如果配置了 proxyTargetClass = true
                    // 则将代理对象放入 ThreadLocal,以方便后续获取,解决代理对象的方法中调用本来其他方法代理失效的问题。
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // 获取原始对象的信息
                target = targetSource.getTarget();
                Class<?> targetClass = (target != null ? target.getClass() : null);
                // 获取符合 AOP 配置切入点的拦截器链,同一个方法可以设置多个 AOP 切入点,多个切入点的顺序可以使用 @Ordered 注解指定,越小越优先
                // 如何判断是否满足切入点的配置?底层是通过 Pointcut 接口的 AspectJExpressionPointcut 来进行条件的判断,先匹配类型,再匹配方法
                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 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);
                }
            }
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值