按照自己的思路去研究Spring AOP原始碼【1】

eaglelihh發表於2021-04-28

一個例子

// 定義一個切面
package cn.eagle.li.source.aspect;

@Component
@Aspect
public class ServiceAspect {
	@Pointcut("execution(* cn.eagle.li.source.service.*.*(..))")
	public void pointCut() {
	}

	@Before("pointCut()")
	public void methodBefore() {
		System.out.println("===== Before =====");
	}

	@After("pointCut()")
	public void methodAfter() {
		System.out.println("===== After =====");
	}

	@AfterReturning("pointCut()")
	public void methodReturn() {
		System.out.println("===== AfterReturning =====");
	}

	@Around("pointCut()")
	public void doAround(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("===== Around before =====");
		pjp.proceed();
		System.out.println("===== Around after =====");
	}
}
// 一個介面
package cn.eagle.li.source.service;
public interface IService {
	void doService();
}

// 一個實現類
package cn.eagle.li.source.service.impl;
@Service
public class ServiceImpl implements IService {
	@Override
	public void doService() {
		System.out.println("do service");
	}
}
// Main類
@Configuration
@ComponentScan(basePackages = {"cn.eagle.li.source"})
@EnableAspectJAutoProxy(exposeProxy = true)
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
		IService service = context.getBean(IService.class);
		service.doService();
	}
}

執行結果如下:

===== Around before =====
===== Before =====
do service
===== AfterReturning =====
===== After =====
===== Around after =====

從@EnableAspectJAutoProxy註解入手

下面是EnableAspectJAutoProxy註解類內容

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
        //代理的實現方式,true為CGLIB, false為JDK,預設false
	boolean proxyTargetClass() default false;
  
 	// 要不要暴露代理物件
	boolean exposeProxy() default false;
}

除了上面兩個引數比較重要外,它還有一個Import註解,在Spring中,只要一種註解組合了另一種註解,它就具有該註解的功能,也就是這個註解擁有了@Import註解的功能。

@Import(AspectJAutoProxyRegistrar.class)

我們看到它import了AspectJAutoProxyRegistrar這個類,我們下面再看看這個類的內容,發現它主要的工作就是註冊一個name為:

org.springframework.aop.config.internalAutoProxyCreator,類為AnnotationAwareAspectJAutoProxyCreator的BeanDefinition。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
             // ......
	}
}
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
public abstract class AopConfigUtils {
	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
}
public abstract class AopConfigUtils {
  
  	public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";
  
        @Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    
                // 註冊 BeanDefinition
                // AUTO_PROXY_CREATOR_BEAN_NAME = org.springframework.aop.config.internalAutoProxyCreator
                // beanDefinition = AnnotationAwareAspectJAutoProxyCreator.class
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}
}

此時有一個疑問:那就是什麼時候呼叫這個方法來載入AnnotationAwareAspectJAutoProxyCreator這個類的BeanDefinition呢?

從下面這張圖可以看到是在容器進行重新整理的時候,呼叫invokeBeanFactoryPostProcessors這個方法來進行執行的,具體的執行過程就不展開了。

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
                                // 在這裡把beandefinition載入
				invokeBeanFactoryPostProcessors(beanFactory);
                                // ......
      }
    }

現在這個類的BeanDefinition準備好了,那什麼時候會建立AnnotationAwareAspectJAutoProxyCreator這個例項,然後載入到容器裡呢?

我們看一下這個類的繼承關係,發現它是一個實現了BeanPostProcessor介面,也就是說它是一個後置處理器。在refresh()方法中有一個步驟是專門用來註冊後置處理器的,也就是registerBeanPostProcessors()這個方法。

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);
        
                                // Register bean processors that intercept bean creation.
                                // 在這裡把BeanPostProcessor載入到容器中
				registerBeanPostProcessors(beanFactory);
                                // ......
      }
    }

在除錯的過程中,發現在PostProcessorRegistrationDelegate這個類下的registerBeanPostProcessors()這個方法下會建立AnnotationAwareAspectJAutoProxyCreator,並把它註冊到容器中,如下圖。

PostProcessorRegistrationDelegate類下
public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
}

經過上面的一個討論,我總結了一下它的一些關鍵觸發路徑,如下:

refresh() -> invokeBeanFactoryPostProcessors() -> AspectJAutoProxyRegistrar.registerBeanDefinitions()
name:"org.springframework.aop.config.internalAutoProxyCreator" beanDefinition:AnnotationAwareAspectJAutoProxyCreator -> registerBeanPostProcessors() -> 建立類例項並載入到容器中

什麼時候會建立代理物件?

容器裡有了AnnotationAwareAspectJAutoProxyCreator這個例項,它具體有什麼用呢,它什麼時候會生成代理物件呢?

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

大家都知道,Spring在建立一個類例項後,會對這個類進行初始化,然後會執行一系列的後置處理器,就在applyBeanPostProcessorsAfterInitialization()這個方法裡面。

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

它會依次地去呼叫每一個後置處理器,當然也包括了我們剛剛註冊的AnnotationAwareAspectJAutoProxyCreator這個後置處理器,具體的執行方法就是postProcessAfterInitialization();

	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;
	}

我們來看一下AnnotationAwareAspectJAutoProxyCreator類的postProcessAfterInitialization這個方法,發現如果沒有包裝過,就把它包裝一下。

	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;
	}
return wrapIfNecessary(bean, beanName, cacheKey);

我們看到它會獲取一些適配這個類的Advices和Advisors,如果不為null,就建立一個代理物件。

	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;
		}

		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
                // DO_NOT_PROXY = 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;
	}
Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
                // ......
		return proxyFactory.getProxy(targetClassLoader);
	}
	public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

Spring AOP有兩種代理類,Jdk代理類和Cglib代理類,具體要看proxyTargetClass這個配置項和這個類是否實現了介面。

	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(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);
		}
	}

我們以JDK動態代理為例,發現它就是用Java的api進行建立的,代理類JdkDynamicAopProxy這個類

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
	@Override
	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);
	}
}

到現在,我們知道,當建立一個bean例項後,在它初始化後,會呼叫每個後置處理器的初始化後的方法

當呼叫AOP的後置處理器的時候,會根據有沒有適配它的advice和advitor來建立代理類

建立代理類的時候,有兩種選擇,一是JDK代理類,二是Cglib代理類

如果proxyTargetClass為false或者這個類沒有實現介面的話,就選擇Cglib代理類,否則選擇JDK代理類。

方法執行時怎麼實現攔截的?

現在我們獲取一個bean時,獲取的就是它的代理類,那在呼叫其方法時,哪些符合的通知是怎麼一步步執行的呢?

我們以JDK代理類為例,我們都知道,在JDK動態代理中,實際執行的時候是執行的代理類的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;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;
			
                        // 如果設定了exposeProxy引數
                        // 這裡暴露了代理物件
                        // AopContext.currentProxy() 獲得
			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...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				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()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}
}

總的看下來,主要關心以下內容:

// 如果設定了exposeProxy引數
// 這裡暴露了代理物件
// AopContext.currentProxy() 獲得
if (this.advised.exposeProxy) {
  // Make invocation available if necessary.
  // 這裡是用ThreadLocal實現的
  oldProxy = AopContext.setCurrentProxy(proxy);
  setProxyContext = true;
}

// 建立攔截器鏈
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();
}

這個執行鏈就是一個陣列,然後一個一個向下執行,根據之前的例子,這個生成的執行鏈如下:

AspectJAroundAdvice MethodBeforeAdviceInterceptor AspectJAfterAdvice AspectJAfterReturningAdvice

最終包裝成ReflectiveMethodInvocation這個類,呼叫其proceed()方法執行,如下:

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {

	public Object proceed() throws Throwable {
		// 攔截器鏈中的最後一個攔截器執行完
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                        // 執行目標方法
			return invokeJoinpoint();
		}

                // 每次執行新的攔截器,下標+1
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			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 {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
                        // 上面的例子每次都會這個方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}
}
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {
	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);
	}
}
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
	public Object invoke(MethodInvocation mi) throws Throwable {
                // 呼叫通知方法
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
                // 下一個攔截器
		return mi.proceed();
	}
}
public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
                        // 下一個攔截器
			return mi.proceed();
		}
		finally {
                        // 呼叫通知方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
		implements MethodInterceptor, AfterAdvice, Serializable {
	public Object invoke(MethodInvocation mi) throws Throwable {
                // 下一個攔截器
		Object retVal = mi.proceed();
                // 呼叫通知方法
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

===== Around before =====
===== Before =====
do service
===== AfterReturning =====
===== After =====
===== Around after =====

從上面可以看出,代理類執行的時候,就是將符合的advice排序得到一個陣列,然後依次的進行執行。

總結

  1. 從EnableAspectJAutoProxy註解入手,Spring會註冊AnnotationAwareAspectJAutoProxyCreator這個類
  2. AnnotationAwareAspectJAutoProxyCreator是個BeanPostProcessor,在初始化後,會呼叫後置處理器,生成代理物件
  3. 在類執行方法時,會生成一個陣列,然後將所有相關的通知一個一個的執行

問題

我看看到上面的順序是 AspectJAroundAdvice MethodBeforeAdviceInterceptor AspectJAfterAdvice AspectJAfterReturningAdvice
但是好多文章都說是AspectJAfterReturningAdvice AspectJAfterAdvice AspectJAroundAdvice MethodBeforeAdviceInterceptor
不同的執行順序會對你的程式會有不同的影響
後續將會寫一篇文章專門介紹這個原因

參考

Spring AOP

SpringAop原始碼分析(基於註解) 一

SpringAop原始碼分析(基於註解) 三

SpringAop原始碼分析(基於註解)四

Spring AOP執行順序

相關文章