Spring AOP实现及运行期调用原理分析

什么是AOP?

面向方面编程(AOP)是对面向对象编程(OOP)的补充,它提供了考虑程序结构的另一种方式。在OOP中模块化的关键单元是类,而在AOP中模块化的单元是方面(在Java中可以视为方法,即函数)。方面支持对跨多种类型和对象的关注点(如事务管理)进行模块化。

Spring AOP模块是Spring两大基础设施之一,这两大基础设施分别IoC和AOP。虽然Spring IoC容器并不依赖于AOP,但AOP补充了IoC,提供了一个功能非常强大的中间件解决方案。

Spring AOP是如何实现的?

说到Spring AOP实现,就不得不提及Spring IoC容器对Bean生命周期优秀的设计和实现。相信很多同学在面试的时候经常被面试官问到Spring中Bean生命周期,但是在日常开发工作中却不怎么使用到这一块,不能太明白这些生命周期有什么作用,那么今天就来一起看看官方(Spring AOP)是如何基于Bean生命周期来对Bean进行增强的。

Bean生命周期有哪些,以及之间的先后顺序是什么,这里就不再做讲解了,不清楚的小伙伴可以查看我的这篇博客《从源码理解Bean的生命周期执行顺序》。

我们在提及Bean生命周期的时候,有一个接口是始终绕不过去的,那就是-BeanPostProcessor。而Spring AOP也正是基于该接口的postProcessAfterInitialization方法来进行Bean的增强(JDK动态代理或者Cglib)。

Spring AOP实现BeanPostProcessor接口的类叫-AbstractAutoProxyCreator,但该类是一个抽象类。在这里插入图片描述
抽象类是无法被实例化的,因此我们无法直接使用该类。通常我们使用的都是该类的子类-AnnotationAwareAspectJAutoProxyCreator。那么该类是如何交由Spring IoC容器管理的呢?答案就在@EnableAspectJAutoProxy注解中,在该注解中向IoC容器导入了一个类-AspectJAutoProxyRegister。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class) // 向IoC容器注册一个Bean
public @interface EnableAspectJAutoProxy {

	/**
	 * 是否强制使用CGLIB来创建代理对象
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 是否导出代理对象
	 */
	boolean exposeProxy() default false;

}

而在AspectJAutoProxyRegistrar 实现的registerBeanDefinitions方法中完成了AnnotationAwareAspectJAutoProxyCreator类的BeanDefinition注册工作。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 通过调用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法来注册AnnotationAwareAspectJAutoProxyCreator的BeanDefinition。
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 删除与本次分析无关代码....
	}

}
// AopConfigUtils
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
	return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {
	// 注册AnnotationAwareAspectJAutoProxyCreator类的BeanDefinition信息到IoC容器
	return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

以上就是对于Spring AOP模块中AnnotationAwareAspectJAutoProxyCreator这个BeanPostProcessor接口实现类是如何注册到Spring IoC容器的原理分析,接下来的分析重点就是该类是如何完成Bean增强的。

前面我们已经提及,Bean的增强是基于该类实现的postProcessAfterInitialization方法来实现的,因此接下来我们分析的重点就是该方法。该接口方法实现位于AbstractAutoProxy类中。

// AbstractAutoProxyCreator#postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) { // 如果传入的Bean不为null
		Object cacheKey = getCacheKey(bean.getClass(), beanName); // 获取缓存Key
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 是否是因循环引用而导致的早期Bean
			return wrapIfNecessary(bean, beanName, cacheKey); // 如果有必要则为Bean创建代理对象
		}
	}
	return bean;
}

首先来分析wrapIfNecessary方法,该方法位于AbstractAutoProxyCreator类中。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	// 如果beanName不为空 并且 targetSourcedBeans包含指定beanName
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	// 如果从advisedBeans中根据cacheKey获取到的boolean值为false,意味不需要为当前Bean创建代理对象,原样返回。
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	// 如果是基础设施Bean(isInfrastructureClass) 或者 需要跳过(shouldSkip),原样返回。
	// 什么是基础设施Bean呢?在SpringAOP中基础设施Bean指的就是实现了Advice或Pointcut或Advisor
	// 或AopInfrastructureBean接口的Bean。
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// 如果有作用于当前Bean的通知(@Before、@After、@Around等),则为当前Bean创建代理对象。
	// 至于Spring AOP是如何根据通知中指定的切点表达式来判断当前Bean是否需要被增强,这里就不展开分析了。
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		// !!! 重点方法,创建代理对象。
		// 该方法参数分别为:bean的Class,beanName,作用于该Bean的通知(多个),将Bean包装为SingletonTargetSource
		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;
}

重点就是createProxy方法,在该方法中完成了Bean的代理对象的创建。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
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,注意这里的重点是proxyTargetClass属性值的拷贝。而这个proxyTargetClass属性值来
	// 源于用户在@EnableAspectJAutoProxy注解中的proxyTargetClass属性配置(默认false)。
	proxyFactory.copyFrom(this);

	if (!proxyFactory.isProxyTargetClass()) {
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}
	// 将MethodInterceptor转换为Advisor
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	// 设置通知器
	proxyFactory.addAdvisors(advisors);
	// 设置TargetSource,这里使用的实现类为SingletonTargetSource
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);
	// 设置冻结状态
	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}
	// 调用代理对象工厂的getProxy方法来创建代理对象
	return proxyFactory.getProxy(getProxyClassLoader());
}

在getProxy方法中通过调用createAopProxy方法返回值的getProxy方法来完成。

// org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}

在createAopProxy方法中,首先判断active属性是否为true,如果不为true,则调用activate方法。该方法(activate)是用来激活代理配置。

// org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();// 激活代理配置
	}
	return getAopProxyFactory().createAopProxy(this);
}

在getAopProxyFactory方法中直接返回了当前实例属性aopProxyFactory的值。那么该属性是何时被赋值的呢?

// org.springframework.aop.framework.ProxyCreatorSupport#getAopProxyFactory
public AopProxyFactory getAopProxyFactory() {
	return this.aopProxyFactory;
}

答案就在ProxyCreatorSupport的无参构造函数中。在前面我们可以看到通过ProxyFactory的无参构造函数手动去new了其实例,而ProxyFactory继承自ProxyCreatorSupport类,因此在其无参构造函数执行前必须先执行其父类无参构造。

public ProxyCreatorSupport() {
	this.aopProxyFactory = new DefaultAopProxyFactory();
}

既然已经知道使用的AopProxyFactory实现类是谁,接下来我们就继续分析其createAopProxy方法,在该方法中完成了AopProxy实现类实例的创建。

// org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	//  是否启用优化(isOptimize) 或者 是否代理目标类(可通过@EnableAspectJAutoProxy注解的proxyTargetClass属性控制),即CGLIB(isProxyTargetClass) 或者 没有用户提供的代理接口
	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);
		}
		// 使用CGLIB来创建代理对象
		return new ObjenesisCglibAopProxy(config);
	}
	// 通常情况下都是使用JdkDynamicAopProxy
	else {
		return new JdkDynamicAopProxy(config);
	}
}

通过JDK动态代理或者CGLIB创建完代理对象后,返回该代理对象。这样保存在IoC容器中的就已不再是原来的Bean,而是被增强后的代理对象。

以上的分析都是为Bean创建代理对象的过程,那么在Bean的方法执行过程中,定义的各种通知是如何调用的呢?这里我们就以根据JDK动态代理创建出的代理对象的invoke方法来进行分析(希望各位同学还记得使用JDK动态代理来创建代理对象时必须要实现InvocationHandler接口,并且通过代理对象来调用目标对象的任何方法时,都是首先调用invoke方法)。

// org.springframework.aop.framework.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 {
		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;
		// 是否需要导出代理对象(可通过@EnableAspectJAutoProxy注解的exposeProxy属性配置)
		if (this.advised.exposeProxy) {
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		// 获取目标对象
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// 根据要执行的方法来动态获取通知器(@Before、@After等)。因为一个类存在多个方法,某些方法需要被增强,
		// 但其它方法可能并不需要被增强。因此需要动态选择作用于该方法的通知。
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// 如果没有作用于目标方法的通知器
		if (chain.isEmpty()) {
			// 直接调用目标方法
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		} else {
			// 如果存在作用于目标方法的通知器,则创建一个ReflectiveMethodInvocation实例,并调用其proceed方法。
			MethodInvocation invocation =
					new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// 在proceed方法中完成了多个通知以及目标方法的调用。
			retVal = invocation.proceed();
		}
		// 获取方法返回值
		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target &&
				returnType != Object.class && returnType.isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			// 如果目标方法的返回值是this,则返回代理对象
			retVal = proxy;
		} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			// 如果方法返回值等于null,但是该方法需要返回值,则抛出异常。
			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);
		}
	}
}

接下来我们就分析下ReflectiveMethodInvocation的proceed方法。

// org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
	// 如果当前拦截器下标 等于 拦截器链的长度减一代表所有拦截器已执行完毕,直接执行目标方法。
	// currentInterceptorIndex 初始值为 -1
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}
	// 先自增currentInterceptorIndex,然后从interceptorsAndDynamicMethodMatchers获取对应下标的通知
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	// 通常这个判断都不会成立,因为使用的都是MethodInterceptor接口实现类
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		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 {
		// 调用MethodInterceptor接口实现类的invoke方法,注意这里传入的方法参数值是this,重点!!!
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

MethodInterceptor接口有五个主要的接口实现类,分别为MethodBeforeAdviceInterceptor(@Before)、AspectJAfterAdvice(@After)、AfterReturningAdviceInterceptor(@AfterReturning)、AspectJAroundAdvice(@Around)、AspectJAfterThrowingAdvice(@AfterThrowing)。在这里插入图片描述
这些实现类还是比较简单的,这里我们简单看几个。
MethodBeforeAdviceInterceptor :

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

	private final MethodBeforeAdvice advice;
	
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		// 在目标方法执行前,首先执行通知,即@Before注解标注的方法。
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		// 调用传入的MethodInvocation实例的proceed,这又会回调到ReflectiveMethodInvocation的proceed方法(递归)
		return mi.proceed();
	}

}

AspectJAfterAdvice :

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
		   // 调用传入的MethodInvocation实例的proceed,这又会回调到ReflectiveMethodInvocation的proceed方法(递归)
			return mi.proceed();
		} finally {
			// 无论执行目标方法有没有发生异常,都必须要执行@After注解标注方法原因就是因为finally。
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

AspectJAfterThrowingAdvice :

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	// ....

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			// 调用传入的MethodInvocation实例的proceed,这又会回调到ReflectiveMethodInvocation的proceed方法(递归)
			return mi.proceed();
		} catch (Throwable ex) {
			// 如果发生的异常类型是已知的异常类型,则执行@AfterThrowing注解标注的方法
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}

	/**
	 * 判断传入的异常类型是否是已知的异常类型
	 */
	private boolean shouldInvokeOnThrowing(Throwable ex) {
		return getDiscoveredThrowingType().isAssignableFrom(ex.getClass());
	}
}

总结

由于Spring AOP是一个复杂的模块,仅靠一篇博客就完全讲明白,实在不太现实,因此本篇博客重点分析了下为Bean创建代理对象的过程以及运行期的调用,如果您发现文中存在某些错误,敬请在评论区留言指正。

通过以上分析我们可以得知,Spring AOP其实并没有什么神奇的,其也是借助于Spring IoC中Bean生命周期特性来完成“偷梁换柱”,将目标对象替换为代理对象,这样保存在IoC容器中的就是代理对象。

在运行期调用的时候,通过调用的目标方法来动态确定要执行的通知,以@Before通知为例,就是先执行添加了@Before注解的方法,然后再执行目标方法。但是由于AOP定义了多种通知类型,因此这是一个递归调用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值