Spring的AOP调用流程源码分析~

这里我们只对基于注解的AOP进行讲解。

首先定义一个类用于扫描包:

@Service
@ComponentScan(basePackages = {"com.wml"})
public class EnableComponentScan {
}

然后创建一个类开启AOP的注解扫描:

这也是Springboot开启AOP的方式。

@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class EnableAOP {
}

一、@EnableAspectJAutoProxy注解做了什么?

这里@Service会被@ComponentScan注解扫描到,具体如何被扫描的,是从AnnotationConfigApplicationContext入口,在该方法中,会通过ComponentScan注解,然后像解析自定义标签一样,扫描basePackages下的带注解的类,封装为BeanDefinition,然后会遍历这些BeanDefinition,看看其类上有没有@Import@Compontent等注解,如果有,会继续将涉及的类注册到IOC容器中,这里不是本文的重点,可以自己去了解下。

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		this();
		register(annotatedClasses);
		refresh();
	}

因此一定会扫描到EnableAspectJAutoProxy注解,因为该注解上面有@Import注解,就会将EnableAspectJAutoProxy类和引入的AspectJAutoProxyRegistrar封装成BeanDefinition对象。

我们具体看@EnableAspectJAutoProxy注解,到底做了什么:

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

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 *
	 * true
	 * 1、目标对象实现了接口 – 使用CGLIB代理机制
	 * 2、目标对象没有接口(只有实现类) – 使用CGLIB代理机制
	 *
	 * false
	 * 1、目标对象实现了接口 – 使用JDK动态代理机制(代理所有实现了的接口)
	 * 2、目标对象没有接口(只有实现类) – 使用CGLIB代理机制
	 *
	 *
	 */
	boolean proxyTargetClass() default false;

	boolean exposeProxy() default false;

}

继续跟踪@Import引入的AspectJAutoProxyRegistrar类:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		//先看这里,注册注解AOP入口类
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
		...
	}

}

最终会调用下面的方法:

将我们定义的AOP的入口类封装成BeanDefinition

private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

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

		//把AOP入口类封装成beanDefinition对象,要实例化
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		//入口类的beanName名称,将BeanDefinition注册到IOC
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

二、AOP的Demo

我们先来看下AOP的简单使用【仅仅用于讲解】,定义一个切面:

@Component
@Aspect
public class Aspectj {
	//拦截service包下所有类
    @Pointcut("execution(public * com.wml.service.*.*(..))")
    public void pointCut1(){

    }
	//拦截service包下的saveAccount方法
    @Pointcut("execution(public * com.wml.service.*.saveAccount*(..))")
    public void pointCut2(){}
	//使用pointCut2
    @Before("pointCut2()")
    public void beforeAdvice(){
        System.out.println("before前置通知");
    }
	//使用pointCut1
    @Around("pointCut1()")
    public Object aroundAdvice(ProceedingJoinPoint point) throws Throwable {
        System.out.println("around的前置通知");
        Object proceed = point.proceed();
        System.out.println("around的后置通知");
        return proceed;

    }
}
@Service
public class AccountServiceImpl implements AccountService {
    public void saveAccount() {
        System.out.println("saceAccount");
  }
}

启动:

public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ComponentScanBean.class);
        AccountService bean = applicationContext.getBean(AccountService.class);
        bean.saveAccount();
    }

结果:

around的前置通知
before前置通知
saceAccount//被代理方法
around的后置通知

当我们拿到AccountService实例时,通过断点可以看到其是一个代理类型的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5HAs42J1-1586597515084)(C:\Users\MI\AppData\Roaming\Typora\typora-user-images\1586515840827.png)]

那么它原本的实例在哪呢?回顾前面文章讲bean实例化和依赖注入的时候,有个位置是AOP的入口,AOP想要用原类,那么一定在该类实例化和依赖注入完成后才可以用,因此AOP入口是在doCreateBeanpopulateBean方法(实例化后的依赖注入)后进行,即initializeBean方法,如下:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			.....
		}
		else {
			//调用Aware方法
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//调用@PostConstruct,Aware等接口方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//调用InitializingBean接口的afterPropertiesSet方法和init-method
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		.................
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//这里就是AOP的入口了
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

三、AOP入口

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

这里遍历所有的BeanPostProcessor接口,调用postProcessAfterInitialization方法,该方法是bean声明周期中,初始化后的后置操作,这里主要交给其子类AbstractAutoProxyCreator处理:

	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
                //看这个方法
				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;
		}

		//代码1:如果当前bean在切点pointcut表达式范围内,则获得当前bean的切面
		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		//代码2:如果有切面,则生成该bean的代理
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//把被代理对象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;
	}

这个方法定义了AOP的核心流程:

  1. 如果当前类在切点范围内需要增强,则获取该类的切面
  2. 如果有切面,则创建该bean的代理对象返回。

我们首先看第一个重点,获取bean的切面:

四、获取bean的切面Aspect

进入该方法,涉及的类为:AbstractAdvisorAutoProxyCreator

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

继续跟踪:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		//找到工程所有有@Aspectj注解的类封装成Advisor返回
		List<Advisor> candidateAdvisors = findCandidateAdvisors();

		//模糊匹配当前类是否作用的pointcut表达式中
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			//对有@Order@Priority进行排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

该方法主要做了两件事:

  1. 寻找所有被@Aspect注解标注的类,并封装成Advisor返回
  2. 判断当前类是在pointcut表达式范围内

我们先来看是如何寻找@Aspect注解标注的类:

最终会调用如下方法,构造Advisor集合:

4.1 buildAspectJAdvisors 构造切面集合

public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
					//首先获取容器中的所有bean的名称BeanName
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
						if (!isEligibleBean(beanName)) {
							continue;
						}
						// We must be careful not to instantiate beans eagerly as in this case they
						// would be cached by the Spring container but would not have been weaved.
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
						//判断类上是否有@Aspect注解
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {

								//创建获取有@Aspect注解类的实例工厂进行获取
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);

								//创建切面advisor对象
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}

		................缓存的切面aspectNames不为null但是空的,就返回空集合;
            如果有缓存,就调用getAdvisors获取并加入缓存.....
		return advisors;
	}

这个方法我们只要关注第一个if,会遍历当前spring容器中所有的beanName,然后通过MetadataAwareAspectInstanceFactory实例工厂获取切面对象Advisor

4.1.1 getAdvisors

	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		//1.借助工厂获取有@Aspect注解的类Class
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		//2.获取所有有@Aspect注解的类的beanName
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		validate(aspectClass);

		//创建工厂的装饰类,获取实例只会获取一次
		// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
		// so that it will only instantiate once.
		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

		List<Advisor> advisors = new ArrayList<>();

		//3.循环没有@Pointcut注解的方法
		for (Method method : getAdvisorMethods(aspectClass)) {

			//3.1 具体获取
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		// If it's a per target aspect, emit the dummy instantiating aspect.
		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}

		//判断属性上是否有引介注解
		// Find introduction fields.
		for (Field field : aspectClass.getDeclaredFields()) {
			//判断属性上是否有DeclareParents注解,如果有返回切面
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		return advisors;
	}

该方法核心就是:

从刚刚的工厂中获取有@Aspect注解的class对象和beanName,然后遍历该类中没有@PointCut注解的类,也就是我们定义的@Around@Before@After等注解通知的方法,通过getAdvisor创建具体的切面类:

4.1.2getAdvisor 解析通知方法构造切面类

该方法就是对我们有通知的具体的方法进行解析。解析what?无非就是注解信息,啥类型的注解?注解里的参数是啥?

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {

		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

		//代码1:获取pointCut对象【解析注解信息,创建PointCut对象,将解析出来的pointcut表达式设置到对应属性中】
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}

		//创建Aspect切面类,这才是真正的切面类,一个切面类里面肯定要有1、pointCut 2、advice
		//这里pointCut是expressionPointcut, advice 增强方法是 candidateAdviceMethod
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

4.1.2.1 getPointcut 创建pointcut对象

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
		//代码1:并把注解信息封装成AspectJAnnotation对象
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		//代码2:创建一个PointCut类
		AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
		///2.1把前面从注解里面解析的表达式设置进去
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
		if (this.beanFactory != null) {
			ajexp.setBeanFactory(this.beanFactory);
		}
		//将pointCut返回
		return ajexp;
	}

4.1.2.1.1 封装注解信息
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
		for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
			//找到Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
			//注解的方法,并且把注解里面的信息封装成AspectJAnnotation对象
			AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
			if (foundAnnotation != null) {
				return foundAnnotation;
			}
		}
		return null;
	}

ASPECTJ_ANNOTATION_CLASSES存储了切点类以及几个用于增强的注解类,判断当前方法用的是哪个注解,然后进行解析封装成AspectJAnnotation对象返回,如果没有这些注解就返回null

private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

内部会调用return new AspectJAnnotation<>(result);,result就是一个注解类对象,将其封装为AspectJAnnotation:

public AspectJAnnotation(A annotation) {
			this.annotation = annotation;
    		//这里就是判断当前注解是啥类型,取值是枚举类:
    		//AtPointcut, AtAround, AtBefore, AtAfter, AtAfterReturning, AtAfterThrowing
			this.annotationType = determineAnnotationType(annotation);
			try {
				//1. 这里就是解析注解上的value值,即pointcut值,如@Before("pointCut2()")中的pointCut2()或是具体的execution表达式
				this.pointcutExpression = resolveExpression(annotation);
				//2.获取注解上的参数
				Object argNames = AnnotationUtils.getValue(annotation, "argNames");
				this.argumentNames = (argNames instanceof String ? (String) argNames : "");
			}
			catch (Exception ex) {
				throw new IllegalArgumentException(annotation + " is not a valid AspectJ annotation", ex);
			}
		}

这里做的无非就是将注解的类型、pointcut表达式和参数[不重要]封装成AspectJAnnotation对象返回。

这样就拿到了当前增强方法的注解信息(主要是pointcut表达式),回到4.1.2.1,后面就很简单了。

4.1.2.1.2 创建PointCut对象

看上述代码,就是创建了PointCut类AspectJExpressionPointcut,然后将刚刚得到的注解信息中的表达式赋值上去,然后将该类返回就完成了。

		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());

回到4.1.2,拿到pointCut对象后,就开始创建具体的切面类。

4.1.2.2 创建切面类

切面由什么构成?切点pointcut和增强Advice呀,所以封装切面,主要就是封装这两个属性,pointcut前面我们有了,主要的就是创建Advice对象


	public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
		//pointcut类及其他属性赋值
		this.declaredPointcut = declaredPointcut;
		this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
		this.methodName = aspectJAdviceMethod.getName();
		this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
		this.aspectJAdviceMethod = aspectJAdviceMethod;
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		this.aspectInstanceFactory = aspectInstanceFactory;
		this.declarationOrder = declarationOrder;
		this.aspectName = aspectName;

		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// Static part of the pointcut is a lazy type.
			Pointcut preInstantiationPointcut = Pointcuts.union(
					aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

			// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
			// If it's not a dynamic pointcut, it may be optimized out
			// by the Spring AOP infrastructure after the first evaluation.
			this.pointcut = new PerTargetInstantiationModelPointcut(
					this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
			this.lazy = true;
		}
		else {
			// A singleton aspect.
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
			//创建了Advice对象
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}

创建Advice对象
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
		//创建Advice对象
		Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
		return (advice != null ? advice : EMPTY_ADVICE);
	}
getAdvice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		//获取有@Aspect注解的类
		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		//就是前面封装注解信息的方法,这里又进行了一遍
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// If we get here, we know we have an AspectJ method.
		// Check that it's an AspectJ-annotated class
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}

		AbstractAspectJAdvice springAdvice;

		//这里就会根据注解类型【前面说的枚举】创建不同的advice类
		switch (aspectJAnnotation.getAnnotationType()) {
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			case AtAround:
				//实现了MethodInterceptor接口
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtBefore:
				//实现了MethodBeforeAdvice接口,没有实现MethodInterceptor接口
				springAdvice = new AspectJMethodBeforeAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfter:
				//实现了MethodInterceptor接口
				springAdvice = new AspectJAfterAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfterReturning:
				//实现了AfterReturningAdvice接口,没有实现MethodInterceptor接口
				springAdvice = new AspectJAfterReturningAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:
				//实现了MethodInterceptor接口
				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);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}

		//计算argNames和类型的对应关系
		springAdvice.calculateArgumentBindings();

		return springAdvice;
	}

这里我们只要知道是根据注解的类型创建了不同的Advice类,然后返回,而几个Advice类的细节,以及有的实现的MethodInterceptor接口,有的实现的MethodBeforeAdvice接口后面会具体讲解。

到这里就对一个方法完成了全部的解析,并且构造了一个切面对象Advisor,接着会遍历4.1.1中所有的方法构建Advisor对象。

回到4.1.1,拿到Advisor对象。集合,然后就该处理引介注解。

4.1.3 处理引介注解!!!

// Find introduction fields.
		for (Field field : aspectClass.getDeclaredFields()) {
			//判断属性上是否有DeclareParents注解,如果有返回切面
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

4.2 匹配当前bean是否在表达式范围中

最后就回到第四部分,拿到所有Advisor对象后,就要遍历Advisor集合,判断当前类是否在pointcut表达式的范围中,这里进行模糊匹配,了解就好。

如果使用了@Order@Priority注解,就排序后再返回。

回到第三部分,下一步就是如果有切面,则创建该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);
		}

		//1.创建代理工厂
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				//设置proxyTargetClass属性
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		//2. 把advice类型的增强包装成advisor切面
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    	//将所有切面放入代理工厂
		proxyFactory.addAdvisors(advisors);
    	//设置目标类
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		////用来控制代理工厂被配置后,是否还允许修改代理的配置,默认为false
		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		//3.获取代理实例
		return proxyFactory.getProxy(getProxyClassLoader());
	}

5.1 buildAdvisors

buildAdvisors方法 将所有拦截器、增强器、增强方法统一封装advisors

	
	protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
		// Handle prototypes correctly...
		//自定义MethodInterceptor.拿到AnnotationAwareAspectJAutoProxyCreator对象调用setInterceptorNames方法
		Advisor[] commonInterceptors = resolveInterceptorNames();

		List<Object> allInterceptors = new ArrayList<>();
		if (specificInterceptors != null) {
			allInterceptors.addAll(Arrays.asList(specificInterceptors));
			if (commonInterceptors.length > 0) {
				if (this.applyCommonInterceptorsFirst) {
					allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
				}
				else {
					allInterceptors.addAll(Arrays.asList(commonInterceptors));
				}
			}
		}

		Advisor[] advisors = new Advisor[allInterceptors.size()];
		for (int i = 0; i < allInterceptors.size(); i++) {
			//对自定义的advice要进行包装,把advice包装成advisor对象,切面对象
			advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
		}
		return advisors;
	}

5.2.获取代理实例

public Object getProxy(@Nullable ClassLoader classLoader) {
		
		return createAopProxy().getProxy(classLoader);
	}

该方法会根据目标对象是否有接口来判断是采用CgLib代理还是jdk动态代理:

首先看createAopProxy():

5.2.1 createAopProxy创建代理类[cglib或jdk动态代理]

会获取AOP工厂,调用工厂的createAopProxy方法创建实例,this是ProxyCreatorSupport,前面的AOP工厂就是继承了该类,并且该类有AopProxyFactory的引用。

protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}

这里就会根据注解中的ProxyTargetClass属性和目标类是否实现了接口来判断是创建Cglib代理还是JDK动态代理,注意,这里会将config,即我们的代理工厂传入具体的代理类,保存到advised中,而工厂中又保存了所有的切面对象,后面就会用到。

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

5.2.2 拿到代理后的实例

拿到代理对象,就要开始执行对应的代理,以JDK动态代理为例:

JdkDynamicAopProxy#getProxy

public Object getProxy(@Nullable ClassLoader classLoader) {
		
		//通过代理工厂对象advised【上面提到的】得到被代理的对象
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		//这里就是通过JDK的Proxy创建动态代理实例
    	//参数分为:classLoader、被代理的对象、InvocationHandler实例增强
    	//因为当前代理类实现了InvocationHandler接口,因此可以直接传this
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

到这里,就完成了AOP代理的创建,得到了需要增强的类的代理对象。

接着,就是调用invoke方法,进行代理实例的调用,依然以JDK动态代理为例,JdkDynamicAopProxy为Spring中的JDK动态代理类,因此invoke方法一定在该类中,找到它:

六、代理实例调用invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		Object oldProxy = null;
		boolean setProxyContext = false;

		//代码1:从代理工厂中拿到TargetSource,内部保存了被代理的实例bean
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			//被代理对象的equals方法和hashCode方法不能被代理,直接走对应的方法,不走下面的切面。
			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();
			}
			........

			Object retVal;
			//设置exposeProxy属性
			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			//从targetSource拿到被代理实例
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			//代码2:从代理工厂中拿过执行链, Object是一个被包装成MethodInterceptor类型的Advice对象
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);


			//如果该方法没有执行链,则说明这个方法不需要被拦截,则直接反射调用
			if (chain.isEmpty()) {
				
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// 代码3:有调用链,就进行调用
				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())) {
				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);
			}
		}
	}

这里主要做了两个工作:

  1. 拿到被代理类后,就通过代理工厂获取该类的调用链
  2. 如果如果有执行链,说明需要拦截,就进行增强调用。

先看1,获取执行链。

6.1 获取执行链

从该方法获取到后,会存在缓存中。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		//从代理工厂对象config拿到被代理类的所有切面advisors
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;
		//如本例的around和before两个切面
		for (Advisor advisor : advisors) {
			//大部分走这里
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				//通过切面的pointcut判断当前类是否需要拦截,即匹配通配符
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						//再通过pointcut判断当前方法是否需要拦截,因为我们可能只拦截部分方法
						match = mm.matches(method, actualClass);
					}
					
					if (match) {//到这里类和方法都匹配,即该方法要进行拦截

						//获取到切面advisor中的advice,并且包装成MethodInterceptor类型的对象
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			//处理引介切面
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

该方法主要做了如下的事:

  1. 匹配当前类是否和切面的pointcut匹配
  2. 如果1,则判断当前方法是否和切面pointcut匹配
  3. 如果都匹配,则将切面中的各种Advice包装成MethodInterceptor后添加到执行链集合返回。这里主要是为了后面调用的时候可以统一调用。

因此,我们主要来看看如何包装Advice的:

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
    /*
    如果是MethodInterceptor类型的,即前面创建Advice时,几个类实现了MethodInterceptor接口:
   		 AspectJAroundAdvice
		AspectJAfterAdvice
		AspectJAfterThrowingAdvice
    */
		if (advice instanceof MethodInterceptor) {
			//包装成MethodInterceptor
			interceptors.add((MethodInterceptor) advice);
		}

		//这里就是将没有实现MethodInterceptor接口的两个Advice: AspectJMethodBeforeAdvice 和AspectJAfterReturningAdvice包装成MethodInterceptor
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
	}

到这里就拿到了当前方法的执行链,如果当类不需要增强,则就不会被匹配拦截,其执行链也就是空,就会直接反射执行其本身的方法,如果不为空,就需要执行代理增强的方法:

6.2 链式调用

回到六中的代码3,会将proxy, target, method, args, targetClass, chain几个参数封装为ReflectiveMethodInvocation然后调用proceed方法进行链式调用:

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		//代码1:如果执行链中的advice全部调用完毕,则直接调用joinPoint方法,即被代理的方法本身
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//interceptorsAndDynamicMethodMatchers就是刚刚获取的执行链,有当前方法需要调用的所有Advice
    	//代码2:这里就会按顺序调用里面的advice,然后索引加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 {

			//代码3:调用MethodInterceptor中具体的invoke方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

这里流程也很简单,就是按顺序取刚刚得到的调用链中的Advice,然后转成MethodInterceptor调用对应子类的invoke方法,当调用的索引和调用链集合一样大时,说明所有的Advice都调用完成了,这时就可以执行被代理的方法。

那么有个问题,这里没有for循环,是如何调用多次的呢?其实很简单,已经说了是链式调用,因此调用完上一个Advice后,会在上一个invoke中的最后再调用proceed方法,这时就开始了下一次Advice的调用。

Advice有多个子类,分别对应Before、Around、AfterRturning、AfterThrowing、After等注解增强。

其首先会调用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);
        //反射调用Around注解中的方法
		return invokeAdviceMethod(pjp, jpm, null, null);
	}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
			// TODO AopUtils.invokeJoinpointUsingReflection
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
		}
}

这就执行了文章一开始写的Demo中的System.out.println("around的前置通知");,然后走到Object proceed = point.proceed();又会回到proceed方法,继续调用,接着就会调用@Before注解的方法,执行System.out.println("before前置通知");,之后又会调用proceed()继续上面的流程片【如下】。这时全部Advice已经调用完毕,就会执行被代理的方法,执行System.out.println("saveAccount............");,然后从@Around的proceed()返回执行System.out.println("around的后置通知");结束调用。

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

但是@AfterReturning这种需要在被代理方法执行后再执行的Adivice怎么办呢?看一下吧:

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

可以看到,如果调用到该方法,则执行再次进入proceed方法,其实就相当于@Around中的proceed方法的作用,等全部执行完后,再执行后置通知。对应@AfterThrowing是一样的道理,只是将proceed放入了try中,在finally中会判断是否发生异常,如果发生异常,就执行@AfterThrowing注解的方法。

七、总结

AOP入口前,会扫描basepackages下的所有带注解的类,@Component@Configuration@Bean@Import等,此时就会将开启AOP的注解,以及使用@Import引入的配置类封装成BeanDefinition注册到spring容器中。

  1. 首先在依赖注入后进入AOP的入口
  2. 遍历容器中的beanName,如果bean有@Aspect注解,则通过一个实例工厂进行解析,获取切面集合。
  3. 接着会遍历带@Aspect注解的类中的所有没有@PointCut注解的方法,对方法上的注解解析(主要是Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class)几个注解,将注解的类型、pointcut表达式等封装成AspectJAnnotation,再将pointcut值封装到AspectJExpressionPointcut【是一个PointCut子类】中返回。
  4. 拿到PointCut对象后,再根据注解的类型创建对应的Advice类
  5. 将PointCut和Advice封装为切面Advisor,遍历完方法后会得到一个切面集合
  6. 将当前bean与得到的切面匹配,判断是否在范围内,得到新的切面集合,然后再进行排序
  7. 切面不为空就创建对应的代理
  8. 创建代理时 将所有拦截器、增强器、增强方法统一封装为advisors,放入代理工厂,通过代理工厂获取代理类
  9. 代理工厂通过ProxyTargetClass的取值和是否实现了接口,创建cglib代理或JDK动态代理类,再根据代理类创建代理对象返回
  10. 进行链式调用
    • ​ 分别匹配类和类中的方法是否需要拦截,如果需要,则将切面中的Advice封装为MethodInterceptor类型的执行链集合
    • 执行链不为空,说明需要拦截,按索引获取Advice,调用对应的invoke方法,每个子类的invoke方法中会继续调用proceed实现链式调用,直到索引值和advice集合相同,说明所有Advice执行完毕,此时就可以调用被代理对象。@AfterReturning@AfterThrowing会在被代理方法执行完毕或前面调用出现异常时分别调用。

OK。到这AOP的调用流程就讲解完毕了。

发布了75 篇原创文章 · 获赞 13 · 访问量 8369

猜你喜欢

转载自blog.csdn.net/weixin_43696529/article/details/105456237
今日推荐