Spring AOP源码解析

创建AOP代理

上面讲解了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,这个类到底做了什么工作来完成AOP的操作呢,首先我们看看AnnotationAwareAspectJAutoProxyCreator的类层次结构。
在这里插入图片描述

在类的层级中,我们可以看到AnnotationAwareAspectJAutoProxyCreator实现了BeaPostProcessor接口,而实现BeanPostProcessor接口后,当Spring加载这个Bean时会在实例化前调用其postProcessAfterInitialization方法,这个方法里面包含了AOP的逻辑。

AbstractAutoProxyCreator#postProcessAfterInitialization

/**
 * 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) {
		    // 如果它适合被代理,则需要封装指定Bean
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

AbstractAutoProxyCreator#wrapIfNecessary

/**
 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
 * @param bean the raw bean instance
 * @param beanName the name of the bean
 * @param cacheKey the cache key for metadata access
 * @return a proxy wrapping the bean, or the raw bean instance as-is
 */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	// ...

	// Create proxy if we have advice.
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		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;
}

wrapIfNecessary中,我们看到了代理创建的雏形。真正创建代理是从getAdvicesAndAdvisorsForBean开始的,创建代理包含了两个步骤:

  1. 获取增强方法或者增强器
  2. 根据获取的增强进行代理

虽然上面两个步骤看起来简单,但每个步骤中都包含了大量复杂的逻辑。首先我们看看获取增强方法的实现逻辑:

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

	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	if (advisors.isEmpty()) {
		return DO_NOT_PROXY;
	}
	return advisors.toArray();
}

/**
 * Find all eligible Advisors for auto-proxying this class.
 * @param beanClass the clazz to find advisors for
 * @param beanName the name of the currently proxied bean
 * @return the empty List, not {@code null}, if there are no pointcuts or interceptors
 */
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

对于获取指定bean的增强方法包含两个步骤,通过findCandidateAdvisors获取所有的增强,以及通过findAdvisorsThatCanApply获取适用于当前bean的增强。

获取增强器

普通增强器的获取通过getAdvisor方法实现,实现步骤包括对切点的注解的获取以及根据注解信息生成增强。

/**
 * Build a Spring AOP Advisor for the given AspectJ advice method.
 * @param candidateAdviceMethod the candidate advice method
 * @param aspectInstanceFactory the aspect instance factory
 * @param declarationOrder the declaration order within the aspect
 * @param aspectName the name of the aspect
 * @return {@code null} if the method is not an AspectJ advice method
 * or if it is a pointcut that will be used by other advice but will not
 * create a Spring advice in its own right
 */
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
		int declarationOrderInAspect, String aspectName) {

	validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    // 切点信息的获取
	AspectJExpressionPointcut expressionPointcut = getPointcut(
			candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
	if (expressionPointcut == null) {
		return null;
	}
    // 根据切点信息生成增强器
	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

切点信息的获取,就是指定注解的表达式信息的获取,如@Before("anyPublicMethod()")

private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
	for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
		AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
		if (foundAnnotation != null) {
			return foundAnnotation;
		}
	}
	return null;
}

根据切点信息生成增强。所有的增强都由Advisor的实现类instantiationModelAwarePointcutAdvisorImpl统一封装的。在封装过程中还顺便完成了对于增强器的初始化,因为不同的增强所体现的逻辑是不同的(比如@Before和@After标签的不同就是增强器增强的位置不同),所以就需要不同的增强器来完成不同的逻辑。

而根据注解中的信息初始化对应的增强器就是在instantiateAdvice函数中实现的。

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
	Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
			this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
	return (advice != null ? advice : EMPTY_ADVICE);
}
	
/**
 * Build a Spring AOP Advice for the given AspectJ advice method.
 * @param candidateAdviceMethod the candidate advice method
 * @param expressionPointcut the AspectJ expression pointcut
 * @param aspectInstanceFactory the aspect instance factory
 * @param declarationOrder the declaration order within the aspect
 * @param aspectName the name of the aspect
 * @return {@code null} if the method is not an AspectJ advice method
 * or if it is a pointcut that will be used by other advice but will not
 * create a Spring advice in its own right
 */
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
	// ...
	
	AbstractAspectJAdvice springAdvice;

	switch (aspectJAnnotation.getAnnotationType()) {
		case AtPointcut:
			if (logger.isDebugEnabled()) {
				logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
			}
			return null;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		default:
			throw new UnsupportedOperationException(
					"Unsupported advice type on method: " + candidateAdviceMethod);
	}
	
    // ...

	return springAdvice;
}

从函数中可以看到,Spring会根据不同的注解生成不同的增强器,例如@Before会对应AspectJMethodBeforeAdvice,在AspectJMethodBeforeAdvice中完成了增强方法的逻辑,调用了增强方法。

// Spring AOP advice that wraps an AspectJ before method.
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
    //...

	@Override
	public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}
    // ...
}

protected Object invokeAdviceMethod(@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
		throws Throwable {
	return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

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 ex) {
	    // ...
	}
}

寻找匹配的增强器

前面的函数中已经完成了所有增强器的解析,但是对于所有增强器来说,并不一定都适用于当前Bean。还要挑选出满足我们配置的通配符的增强器。

/**
 * Search the given candidate Advisors to find all Advisors that
 * can apply to the specified bean.
 * @param candidateAdvisors the candidate Advisors
 * @param beanClass the target's bean class
 * @param beanName the target's bean name
 * @return the List of applicable Advisors
 */
protected List<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	}finally {
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}

创建代理

获取了所有对应bean的增强器后,便可以进行代理的创建了。

/**
 * Create an AOP proxy for the given bean.
 * @param beanClass the class of the bean
 * @param beanName the name of the bean
 * @param specificInterceptors the set of interceptors that is specific to this bean (may be empty, but not null)
 * @param targetSource the TargetSource for the proxy, already pre-configured to access the bean
 * @return the AOP proxy for the 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());
}                                                       

由于Spring中涉及过多的拦截器,增强器,增强方法等方式来对逻辑进行增强,所以非常有必要统一封装成Advisor来进行代理的创建。

代理类的创建及处理,Sring委托给了ProxyFactory去处理,createProxy主要是对ProxyFactory的初始化操作,为真正的代理创建做好准备,这些初始化操作包括以下内容:

  1. 获取当前类中的属性
  2. 添加代理接口
  3. 封装Advisor并加入到ProxyFactory中
  4. 设置要代理的类
  5. 进行获取代理操作
/**
 * Create an {@link AopProxy} for the given AOP configuration.
 * @param config the AOP configuration in the form of an AdvisedSupport object
 * @return the corresponding AOP proxy
 * @throws AopConfigException if the configuration is invalid
 */
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)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

至此已经完成了代理的创建。Spring代理中有JDKProxy的实现和CglibProxy的实现,Spring通过上面的判断逻辑进行选取。

从if中的判断条件可以看到3个方面影响着Spring的判断。

  • optimize:控制通过CGLIB创建的代理是否使用激进的优化策略。(这个属性仅用于CGLIB代理,对于JDK动态代理无效)
  • proxyTargetClass:此属性设置为true时,CGLIB代理将被创建(目标类本身被代理,而不是目标类的接口)。设置方式:<aop:aspectj-autoproxy proxy-target-class="true"/>
  • hasNoUserSuppliedProxyInterfaces:是否存在代理接口

Spring会选择JDK还是Cglib:

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
  • 如果目标对象没有实现接口,必须采用CGLIB类库。Spring会自动在JDK动态代理和CGLIB之间转换。

JDK动态代理和CGLIB字节码生成的区别

  • JDK动态代理只能针对实现了接口的类生成代理,而不能针对类
  • CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法不要声明成final
获取JDK代理

JDK代理创建的过程中,对于InvocationHandler的创建是最为核心的,在自定义的InvocationHandler中需要重写3个函数。JDKDynamicAopProxy会把AOP的核心逻辑写在其中。

  1. 构造函数,将代理的对象传入
  2. invoke方法,此方法中实现了AOP增强的所有逻辑。
  3. getProxy方法,此方法不能少。
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
	}
	
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}
	
	/**
	 * Implementation of {@code InvocationHandler.invoke}.
	 * <p>Callers will see exactly the exception thrown by the target,
	 * unless a hook method throws an exception.
	 */
	@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // ...
		try {
			// ...
			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			//  获取当前方法的拦截器链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				// 如果没有发现任何拦截器,那么直接调用切点方法
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				// 将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行链接表用拦截器
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				// 执行拦截器链
				retVal = invocation.proceed();
			}
			// ...
			return retVal;
		}
	}
}

上面的函数中最主要的工作就是创建了一个拦截器链,并使用ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐一调用。

CGLIB代理

CGLIB是一个高性能的代理生成包,CGLIB包的底层通过使用字节码处理框架ASM,来转换字节码并生成新的类。

**
 * General purpose AOP callback. Used when the target is dynamic or when the
 * proxy is not frozen.
 */
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

	private final AdvisedSupport advised;

	public DynamicAdvisedInterceptor(AdvisedSupport advised) {
		this.advised = advised;
	}

	@Override
	@Nullable
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		// ...
		try {
			// ...
			Class<?> targetClass = (target != null ? target.getClass() : null);
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
			Object retVal;
			// Check whether we only have one InvokerInterceptor: that is,
			// no real advice, but just reflective invocation of the target.
			if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = methodProxy.invoke(target, argsToUse);
			}
			else {
				// We need to create a method invocation...
				retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
			}
			retVal = processReturnType(proxy, target, method, retVal);
			return retVal;
		}
		// ...
	}
}

CGLIB的实现与JDK方式实现代理中的invoke方法大同小异,都是首先构造链,然后封装此链进行串联调用。稍有区别的就是在JDK中直接构造ReflectiveMethodInvocation,而在cglib中使用CglibMethodInvocationCglibMethodInvocation继承自ReflectiveMethodInvocation,但是proceed方法没有重写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值