[spring 源码研读] AOP-三步走?

569 阅读9分钟

本文将基于java-config(注解)研读 spring-AOP 源码

AOP的使用

  1. 配置类上添加@EnableAspectJAutoProxy注解 [开启AOP功能]
  2. AOP bean对象添加@Aspect注解
    @Aspect
    @Component
    public class AOPTest {
         @Pointcut("execution(* com.zhouxh.service.componentTest.*(..))")
         private void pointCut(){
    
         }
         @Before(value = "pointCut()")
         public void before(){
             System.out.println("aop Before start");
         }
    
         @After(value = "pointCut()")
         public void after(){
             System.out.println("aop After start");
         }
    
         @Around(value = "pointCut()")
         public void around(ProceedingJoinPoint joinPoint) throws Throwable {
             System.out.println("aop Around start");
             joinPoint.proceed();
             System.out.println("aop Around end");
         }
         @AfterReturning(value = "pointCut()")
         public void afterReturning(){
             System.out.println("aop AfterReturning start");
         }
         @AfterThrowing(value = "pointCut()")
         public void afterThrowing(){
             System.out.println("aop AfterThrowing start");
         }
    }
    

1. 加载切面

  1. 我们再开启AOP功能时,在配置类上添加了@EnableAspectJAutoProxy注解。该注解在配置类被解析时,会在spring容器中添加一个AnnotationAwareAspectJAutoProxyCreator后置处理器。
    @EnableAspectJAutoProxy
    
    进入该注解,我们可以看到该注解向spring 容器中注入了AspectJAutoProxyRegistrar
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    
    进入AspectJAutoProxyRegistrar类,只有一个构造函数。
    这个函数做了两件事情:
    • 在spring中注入了AnnotationAwareAspectJAutoProxyCreator后置处理器
    • 判断是否设置proxyTargetClass 和 exposeProxy属性
      • proxyTargetClass 属性,默认为false,如果为true时,表示相关bean对象动态代理强制使用CGLIB
      • exposeProxy属性,默认为false,如果为true,有jdk动态代理生成bean对象出现方法内部调用时,也会触发AOP功能。
    public void registerBeanDefinitions(
    	AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    	// 在spring中注入了AnnotationAwareAspectJAutoProxyCreator后置处理器
    	AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    	// 获取注解@EnableAspectJAutoProxy
    	AnnotationAttributes enableAspectJAutoProxy = 
        		AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    	if (enableAspectJAutoProxy != null) {
       		// 判断是否设置proxyTargetClass 和 exposeProxy属性
    		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
    			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    		}
    		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
    			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    		}
    	}
    }
    
  2. 《spring IOC源码解析》这篇文章中,我们知道spring_bean第一次初始化会调用createBean()方法创建一个bean实例。在bean被创建【doCreateBean方法】前,通过spring提供的拓展点【resolveBeforeInstantiation方法】,将切点和通知包装成Advisors
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    	throws BeanCreationException {
    
    /**
     * 省略部分不相干代码
     */
    try {
    	// spring 容器提供的拓展点,会在此处运行spring前置处理器
    	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    	if (bean != null) {
    		return bean;
    	}
    }catch (Throwable ex) {}
    
    try {
    	// 创建一个bean实例
    	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    	if (logger.isTraceEnabled()) {
    		logger.trace("Finished creating instance of bean '" + beanName + "'");
    	}
    	return beanInstance;
    }catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
    	// 省略
    }catch (Throwable ex) {
    	// 省略
    }
    
    进入 resolveBeforeInstantiation方法,最终调用 applyBeanPostProcessorsBeforeInstantiation 方法循环调用所有的前置处理器。
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    	for (BeanPostProcessor bp : getBeanPostProcessors()) {
    		if (bp instanceof InstantiationAwareBeanPostProcessor) {
    			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    			Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
    			if (result != null) {
    				return result;
    			}
    		}
    	}
    	return null;
    }
    
    也就是在这里调用了我们在@EnableAspectJAutoProxy注解,给spring容器中添加的AnnotationAwareAspectJAutoProxyCreator后置处理器。
    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;
    		}
    		// isInfrastructureClass 判断当前beanClass是否被@Aspectj注释,是 返回true,否则返回false
    		// AOP 类会被添加到缓存中,然后 保存在advisedBeans缓存中
    		// shouldSkip()方法解析各通知,并与切点一起包装成Advisors
    		if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    			this.advisedBeans.put(cacheKey, Boolean.FALSE);
    			return null;
    		}
    	}
    	```
       	省略了部分代码
    	```
    	return null;
    }
    
    shouldSkip()方法解析各通知,并与切点一起包装成Advisors
    protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    	// TODO: 查询所有的通知并添加到缓存中,方便调用时获取。
    	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    	for (Advisor advisor : candidateAdvisors) {
    		// 判断AOP是否是通过xml配置的,如果是返回true 【为了兼容xml】
    		if (advisor instanceof AspectJPointcutAdvisor &&
    				((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
    			return true;
    		}
    	}
    	return super.shouldSkip(beanClass, beanName);
    }
    
    findCandidateAdvisors()方法查询所有的通知并添加到缓存中,方便调用时获取。
    protected List<Advisor> findCandidateAdvisors() {
    	// 查找所有继承了 Advisor.class的类【我们通过注解的形式,所以此处查询为空】
    	List<Advisor> advisors = super.findCandidateAdvisors();
    	// Build Advisors for all AspectJ aspects in the bean factory.
    	if (this.aspectJAdvisorsBuilder != null) {
        	// 真正生效的是 buildAspectJAdvisors() 解析变创建 advisors
    		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    	}
    	return advisors;
    }
    
    通过aspectJAdvisorsBuilder.buildAspectJAdvisors()创建advisors并添加到缓存中。
    • this.advisorFactory.getAdvisors(factory)通过 解析切面类中方法上的注解 获取通知切点一起封装到advisor中,将所有advisors根据 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 的顺序进行排序。
    • 并将adviors保存在advisorsCache缓存中
    public List<Advisor> buildAspectJAdvisors() {
    	···
    	此处省略部分判断代码
       	···
    	// 通过解析class类中的方法上的注解 根据 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 排序
    	List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
    	if (this.beanFactory.isSingleton(beanName)) {
    		// 将通知和切点 与 当前bean 一起保存在advisorsCache 缓存中
    		this.advisorsCache.put(beanName, classAdvisors);
    	}
    	···
       	此处省略部分代码
       	···
    }
    

2. 创建代理

spring_bean被创建大致可以分为三步:1. bean的实例化;2. bean属性的注入;3. bean的初始化

AOP 创建动态代理在第三步:bean的初始化【exposedObject = initializeBean(beanName, exposedObject, mbd);

在bean的初始化完成之后,spring提供了一个调用后置处理器的拓展点,就在此处spring会调用AnnotationAwareAspectJAutoProxyCreator后置处理器的后置处理方法。

让我们来追溯源码!

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
	···
	省略部分代码:完成spring_bean的初始化工作
	···
	// 在这之前,bean的初始化已经完成。
	// spring提供的拓展点,调用后置处理器的后置处理方法
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}

applyBeanPostProcessorsAfterInitialization方法中循环所有后置处理器并调用对应的后置处理方法。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessAfterInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

getBeanPostProcessors()获取所有的后置处理器,其中就有 AnnotationAwareAspectJAutoProxyCreator

通过调用父类AbstractAutoProxyCreator.postProcessAfterInitialization()方法 ---> 最终调用wrapIfNecessary()方法生成动态代理。

 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;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
    // 不需要AOP增强的类,直接返回原始对象,不需要动态代理
	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;
	}

	// 如果需要AOP 增强,创建动态代理
   	// 通过 AspectJ 的 api 判断当前类中哪些方法符合哪些通知【通过切点表达式,选择需要增强的内容】
	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;
}

看到这里我们还有一个疑问:AOP动态代理是怎么选择JDK动态代理 还是 CGLIB动态代理的?

继续跟进createProxy()方法,最终进入DefaultAopProxyFactory.createAopProxy()方法

  • isProxyTargetClass() ----> 我们在@EnableAspectJAutoProxy()注解中设置 proxyTargetClass = true;
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    
  • hasNoUserSuppliedProxyInterfaces() ----> true 表示 当前增强类没有实现任何接口
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.");
		}
		// 如果目标增强类,是一个接口 或者 是一个代理类 也会使用JDK动态代理
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

看完这部分代码我们也能得出上面问题的答案了

  1. 如果在开启AOP的注解@EnableAspectJAutoProxy(proxyTargetClass = true)中添加了proxyTargetClass = true,那么spring会使用CGLIB动态代理。
  2. 如果目标增强类没有继承任何接口,那么spring会使用CGLIB动态代理。
  3. 如果目标增强类,是一个接口或者是一个代理类,也会使用JDK动态代理
  4. 否则,会使用JDK动态代理

3. 调用代理

我们知道被代理类的方法被执行时,会先调用代理类的代理方法【jdk动态代理的invoke()/CGLIB动态代理的intercept()】。

我们将以CGLIB动态代理为例,研读Spring AOP是如果调用代理的。

当被增强类的方法被执行时,spring会先调用CglibAopProxy的内部类DynamicAdvisedInterceptor.intercept()方法

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) {
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);
		// 加载切面时,封装好的adviors集合
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
		// 如果没有封装好的adviors,直接调用对应方法
		if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = methodProxy.invoke(target, argsToUse);
		}
		else {
			// AOP 执行通知的入口
			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) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

以上代码核心在于:retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 该方法是 AOP 执行通知的入口。

public Object proceed() throws Throwable {
	// currentInterceptorIndex 初始化时为 -1
	// 如果执行到AOP中声明的最后一个通知,调用目标方法。
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		// 调用目标增强方法
		return invokeJoinpoint();
	}
	// interceptorsAndDynamicMethodMatchers 包含所有的通知的集合,每次获取下一个通知
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {	
	// 省略部分代码
	}else {
		// 在此处调用对应通知的对应类
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

invoke()方法会更根据下图顺序依次调用。
interceptorsAndDynamicMethodMatchers中的对象

调用时序图

环绕通知类 - AspectJAroundAdvice

该类没有什么特殊的方法,就是调用AOP中被@Around注释的方法

public Object invoke(MethodInvocation mi) throws Throwable {
	if (!(mi instanceof ProxyMethodInvocation)) {
		throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
	}
	ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
	ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
	JoinPointMatch jpm = getJoinPointMatch(pmi);
   	// 调用环绕通知方法
	return invokeAdviceMethod(pjp, jpm, null, null);
}

在环绕通知方法中,先进行前置通知,然后唤醒一个通知,最后进行后置通知。

@Around(value = "pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
	System.out.println("aop Around start");
	joinPoint.proceed();
	System.out.println("aop Around end");
}

前置通知 - MethodBeforeAdviceInterceptor

先调用AOP中被@Before注释的方法,然后唤醒下一通知

public Object invoke(MethodInvocation mi) throws Throwable {
	this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
	return mi.proceed();
}

后置通知 - AspectJAfterAdvice

先唤醒下一通知,再调用AOP中被@After注释的方法。

public Object invoke(MethodInvocation mi) throws Throwable {
	try {
		return mi.proceed();
	}
	finally {
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}
}

后置返回通知 - AfterReturningAdviceInterceptor

唤醒下一通知,再调用AOP中被@AfterReturning注释的方法。

public Object invoke(MethodInvocation mi) throws Throwable {
	Object retVal = mi.proceed();
	this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
	return retVal;
}

后置异常通知 - AspectJAfterThrowingAdvice

先执行下一通知,如果出现异常,再执行@AfterThrowing注释的方法。

public Object invoke(MethodInvocation mi) throws Throwable {
	try {
		return mi.proceed();
	}
	catch (Throwable ex) {
		if (shouldInvokeOnThrowing(ex)) {
			invokeAdviceMethod(getJoinPointMatch(), null, ex);
		}
		throw ex;
	}
}

在唤醒下一通知前,会判断是否存在下一通知,如果不存在,直接调用目标增强方法。

该判断在ReflectiveMethodInvocation.proceed()方法中

public Object proceed() throws Throwable {
	// currentInterceptorIndex 初始化时为 -1
	// 如果执行到AOP中声明的最后一个通知,调用目标方法。
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		// 调用目标增强方法
		return invokeJoinpoint();
	}
	····
    ····
}

总结

  1. spring会在doCreateBean之前,会调用 spring 提供的拓展点【resolveBeforeInstantiation】,从所有 beanDefinitionMap 中获取所有的 Object 类型的类,循环判断并获取哪个类被 @Aspectj 注解注释。然后解析该类中被 @Before、@After、@Around、@AfterReturning、@AfterThrowing 注解注释的方法,并与 @Pointcut 注释的切点一起封装在 adviors 中。

  2. 在 spring 初始化方法中,调用所有后置处理器的后置处理方法,获取所有的 adviors 和当前类进行匹配【匹配方法是调用AspectJ的内部API】。匹配成功的类再由 AOPProxyFactory 根据【是否有接口、是否有proxyTargetClass = true】选择使用CGLIB动态代理还是JDK动态代理。

  3. 在目标增强方法被执行时,spring 会将adviors转换成Interceptor,然后通过责任链的模式一次进行调用。