您现在的位置是:首页 >技术交流 >Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut网站首页技术交流

Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut

程序源仔 2024-06-19 13:56:23
简介Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut

目录

1. 前言

2. 源码分析

2.1. AnnotationAwareAspectJAutoProxyCreator

2.1.1. findCandidateAdvisors()

2.1.2. buildAspectJAdvisors()

2.2. AbstractAdvisorAutoProxyCreator

2.3. AbstractAutoProxyCreator


1. 前言

在上篇文章中,Spring AOP源码分析篇一:@EnableAspectJAutoProxy的来龙去脉讲述了AOP的开端,其实就是注册了AnnotationAwareAspectJAutoProxyCreator的beanDefinition到容器中,并且在文章结尾处还给出了这个类的继承关系,这个类和他的父类们极为重要,负责把切面类bean的通知(advice)找出来,并用这些通知们生成代理,本文主要围绕他们去开展。

老规矩,先祭出流程图

看不清没关系,奉上高清链接

aop创建动态代理流程| ProcessOn免费在线作图,在线流程图,在线思维导图

Spring AOP流程

  • 在getBean()生命周期初始化后,执行后置处理器AbstractAutoProxyCreator#postProcessAfterInitialization()方法,找到所有的切面 bean(被@Aspect注解的bean),并遍历每个切面的所有方法,根据 @Before, @After 等advice注解生成对应的 Advisor(排除@Pointcut注解的方法)。
  • 遍历 Advisor 数组,找到和当前bean匹配的advisors。
  • 如果能符合当前bean匹配的advisors,就把这些过滤好的advisors用作生成aop对象(AOP生成对象有jdk和cglib两种方式)

而上面三步可以用下面的图来讲解,这样就能很清晰的看到AnnotationAwareAspectJAutoProxyCreator以及父类在aop流程的作用了

这样看觉得还不够细的话,下面给个更细的图

紫色部分(AnnotationaWareAspectJAutoProxyCreator):获取所有的advisors

粉色部分(AbstractAdvisorAutoProxyCreator):根据当前bean过滤并匹配紫色部分拿到的advisors

青色部分(AbstractAutoProxyCreator):将过滤好的advisors拿来创建aop对象

所以本文打算用逆序的方法讲起,就是先讲紫色部分,再讲粉色部分,最后再讲青色部分 

2. 源码分析

2.1. AnnotationAwareAspectJAutoProxyCreator

从上面图中可知,流程的入手点是AnnotationAwareAspectJAutoProxyCreator类的findCandidateAdvisors()方法,这个方法有两步操作

1.执行父类AbstractAutoProxy#findCandidateAdvisors()方法,主要是获取配置在xml中的Advisor(纯POJO切面)原生接口的AOP的Advisor。

2.调用buildAspectJAdvisors()方法,这个方法才是我们本次重点流程,因为一般我们使用的都是@Aspect、@Before、@After等注解,就是在这里解析的并获取所有advisor。

我们看一下findCandidateAdvisors()方法的源码

protected List<Advisor> findCandidateAdvisors() {
    // 找出xml配置的Advisor和原生接口的AOP的Advisor   找出事务相关的advisor
    // 先找到所有Advisor类型的Bean对象
    List<Advisor> advisors = super.findCandidateAdvisors();

    // 再从所有Aspect切面中解析得到Advisor对象
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    //返回我们所有的通知
    return advisors;

2.1.1. findCandidateAdvisors()

在讲源码前,我们先看看两个demo,如下所示

1、纯POJO切面

public class MyAspectV2 {

    //前置增强
    public void asBefore(){
        System.out.println("这是前置增强");
    }
    //后置增强
    public void asAfterReturning(){

        System.out.println("这是后置增强");
    }

}
<bean id="myAspectV2" class="com.xiaoyuanzai.aspect.MyAspectV2"></bean>

<!-- aop的配置 -->
<aop:config>
  <aop:pointcut expression="execution(public void com.xiaoyuanzai.service.UserService.test())" id="pointcut"/>
  <aop:aspect ref="myAspectV2">
  <aop:before method="asBefore" pointcut-ref="pointcut"/>
  <aop:after-returning method="asAfterReturning" pointcut-ref="pointcut"/>
  </aop:aspect>
</aop:config>

2、原生接口的AOP

public class MyMethodBeforeAdvice implements org.springframework.aop.MethodBeforeAdvice {

    @Override
    public void before( Method arg0, Object[] arg1, Object arg2)
    throws Throwable {
        System.out.println("save前置内容");
    }

}
<bean id="before" class="com.xiaoyuanzai.aspect.MyMethodBeforeAdvice"></bean>

<aop:config>
  <aop:pointcut expression="execution(public void com.xiaoyuanzai.service.UserService.test())" id="pointcut"/>
  <aop:advisor advice-ref="before" pointcut-ref="pointcut"/>
</aop:config>

从上面demo就能很清晰看到纯POJO切面和原生接口的AOP的区别。

现在正式看一下它的findEligibleAdvisors()方法

protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    /**
    * 通过 通知者探测器来帮助我们找到通知,advisorRetrievalHelper在什么时候初始化的?
    */
    return this.advisorRetrievalHelper.findAdvisorBeans();
}


/**
 * this.advisorRetrievalHelper.findAdvisorBeans()的源码
 */
public List<Advisor> findAdvisorBeans() {

    
	// 用来保存我们的Advisor全类名		
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
      //获取advisor类型的beanName
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    //若在容器中没有找到,直接返回一个空的集合
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        //默认都是true
        if (isEligibleBean(name)) {
            //是不是正在创建的bean
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping currently created advisor '" + name + "'");
                }
            }
                //不是的话
            else {
                try {
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        String bceBeanName = bce.getBeanName();
                        if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Skipping advisor '" + name +
                                             "' with dependency on currently created bean: " + ex.getMessage());
                            }
                             continue;
                        }
                    }
                    throw ex;
                }
            }
        }
    }
    return advisors;
}

从上面代码可以看到,要获取到advisor需要两步操作

1、过滤并获取Advisor类型的beanName数组

2、遍历beanName数组,调用getBean()方法获取advisor列表

因为xml不常用,所以这里不深入了,有兴趣的同学自己看源码哈

2.1.2. buildAspectJAdvisors()

这里才是本文的重点

从图中很容易发现,其实就是几层循环而已。

  • 先拿到所有的beanName,遍历beanName,查找被@Aspect注解的类
  • 遍历@Aspect注解的类,拿到它的所有方法,看哪些方法被@Before、@After等通知注解了的(@pointcut注解排除),然后存到一个统一的list里面返回

看下buildAspectJAdvisors()源码

public List<Advisor> buildAspectJAdvisors() {
    // 用于保存切面的名称类级别的缓存,用户缓存已经解析出来的切面信息
    List<String> aspectNames = this.aspectBeanNames;
    // 缓存字段aspectNames没有值 会在第一个单例执行后置处理器(AnnotationAwareAspectJAutoProxyCreator注册之后)的时候就会触发解析切面的操作
    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();

                // 把所有beanNames拿出来遍历,判断某个bean的类型是否是Aspect
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Object.class, true, false);
                for (String beanName : beanNames) {
                    if (!isEligibleBean(beanName)) {
                        continue;
                    }
                    Class<?> beanType = this.beanFactory.getType(beanName, false);
                    if (beanType == null) {
                        continue;
                    }
                    //true: 类型是@Aspect 切面
                    if (this.advisorFactory.isAspect(beanType)) {
                        aspectNames.add(beanName);
                        // //把beanName和class对象构建成为一个AspectMetadata(切面的注解信息)
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);

                        // 如果@Aspect不是perthis、pertarget,那么一个切面只会生成一个对象(单例)
                        // 并且会将该切面中所对应的Advisor对象进行缓存
                        //为单例 bean 实现增强的 Aspect 的逻辑
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            //构建切面注解的实例工厂
                            MetadataAwareAspectInstanceFactory factory =
                            new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // 利用BeanFactoryAspectInstanceFactory来解析Aspect类
                            //真正去获取通知对象们
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            if (this.beanFactory.isSingleton(beanName)) {
                                // 缓存切面所对应的所有Advisor对象
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                            // 为多例 bean 增强的切面的处理逻辑
                        else {
                            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);
                            //它不会缓存advisor, 而是缓存了factory, 需要advisor 的时候,重新调用 getAdvisors() 再生成
                        this.aspectFactoryCache.put(beanName, factory);
                        // 利用PrototypeAspectInstanceFactory来解析Aspect类
                        // PrototypeAspectInstanceFactory的父类为BeanFactoryAspectInstanceFactory
                        // 这两个Factory的区别在于PrototypeAspectInstanceFactory的构造方法中会判断切面Bean是不是原型,除此之外没有其他区别
                        // 所以主要就是BeanFactoryAspectInstanceFactory来负责生成切面实例对象
                        advisors.addAll(this.advisorFactory.getAdvisors(factory));
                    }
                    }
                    }
                        this.aspectBeanNames = aspectNames;
                        return advisors;
                    }
                    }
                    }

                        if (aspectNames.isEmpty()) {
                        return Collections.emptyList();
                    }

                        // 如果切面已经找到过了,那么则遍历每个切面是否缓存了对应的Advisor,如果没有缓存则进行解析得到Advisor
                        List<Advisor> advisors = new ArrayList<>();
                        for (String aspectName : aspectNames) {
                        //从缓存中获取advisor
                        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
                        if (cachedAdvisors != null) {
                        advisors.addAll(cachedAdvisors);
                    }
                        else {
                        MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
                        advisors.addAll(this.advisorFactory.getAdvisors(factory));
                    }
                    }
                        return advisors;
                    }

1、当@Aspect()是单例时,直接缓存advisor

2、当@Aspect()是perthis/pertarget时,是多例bean提供增强的切面类型,缓存的是factory,当需要advisor时,重新调用getAdvisors()生成即可

3、共同点:都是调用了this.advisorFactory.getAdvisors(factory)

4、缓存是以beanName为key去存数据

上面是通过this.advisorFactory.isAspect(beanType)来判断bean是否被@Aspect注解

进入ReflectiveAspectJAdvisorFactory的getAdvisors()看看

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//获取我们的标记为Aspect的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//获取我们的切面类的名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//校验我们的切面类
validate(aspectClass);

// 保证切面Bean对象只会实例化一次
// 一定要注意,这里是直接new出来一个LazySingletonAspectInstanceFactoryDecorator
// 也就是OrderService这个Bean在执行Bean生命周期过程中,会需要判断要不要进行AOP,就会找到切面,
// 发现切面如果是pertarget或perthis,那么就会进入到这个方法,就会new一个LazySingletonAspectInstanceFactoryDecorator
// 对于UserService也是一样的,在它的Bean的生命周期过程中,也会进入到这个方法,也会new一个LazySingletonAspectInstanceFactoryDecorator
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

List<Advisor> advisors = new ArrayList<>();
//获取到切面类中的所有方法,但是该方法不会解析标注了@PointCut注解的方法
for (Method method : getAdvisorMethods(aspectClass)) {
    //挨个去解析我们切面中的方法
    Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
    if (advisor != null) {
        advisors.add(advisor);
    }
}

// @Aspect("pertarget(this(com.xiaoyuanzai.service.UserService))")
// @Aspect("perthis(this(com.xiaoyuanzai.service.UserService))")
// 如果是pertarget或perthis,则会多生成一个Advisor并放在最前面
// 在一个代理对象调用方法的时候,就会执行该Advisor,并且会利用lazySingletonAspectInstanceFactory来生成一个切面Bean
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
    Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
    advisors.add(0, instantiationAdvisor);
}

// Find introduction fields.
// 找到哪些字段上加了@DeclareParents注解,把这些字段以及对于的注解解析封装为Advisor,生成代理对象时会把对于的接口添加到ProxyFactory中
for (Field field : aspectClass.getDeclaredFields()) {
    Advisor advisor = getDeclareParentsAdvisor(field);
    if (advisor != null) {
        advisors.add(advisor);
    }
}

return advisors;
}



private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    List<Method> methods = new ArrayList<>();
    // 拿到切面类中所有没有加@Pointcut的方法
    ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
    // 对方法进行排序,按注解和方法名字进行排序
    if (methods.size() > 1) {
        methods.sort(adviceMethodComparator);
    }
    return methods;
}

private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
			.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));

上面代码大意是,获取@Aspect注解的的bean的所有方法,并筛选这些方法,看看符不符合通知方法@Before、@After(排除@pointcut),符合就生成Advisor放进列表放回,我们看一下流程图

进入getAdvisor()

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

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

    // 获得当前通知的 切点表达式,
    // 但是注意:如果当前方法上是这么写的@After("pointcut()"),那么此时得到的Pointcut并没有去解析pointcut()得到对应的表达式
    AspectJExpressionPointcut expressionPointcut = getPointcut(
        candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }

    // expressionPointcut是pointcut
    // candidateAdviceMethod承载了advice
    // 将切点表达式、 和通知  封装到InstantiationModelAwarePointcutAdvisorImpl对象中
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                                                          this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

这里比较重要,分为两步

1、第一步通过getPointcut()方法生成AspectJExpressionPointcut对象,因为AspectJExpressionPointcutPointcut的子类,也就是说获取到了PointCut切面

2.第二步把AspectJExpressionPointcut作为参数传入,生成Advisor对象(InstantiationModelAwarePointcutAdvisorImpl类型),因为Advisor=Advice+PointCut,所以说在new InstantiationModelAwarePointcutAdvisorImpl()的时候实例化advice的

2.1.2.1. getPoint()

getPoint()方法核心就是实例化point,它分为两步

1、获取AspectJAnnotation实例

2、用AspectJAnnotation实例做参数,实例化一个AspectJExpressionPointcut(切点)对象

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    // 找到aspectJ的注解:
    // @Pointcut  @Around @Before @After  @AfterReturning  @AfterThrowing
    AspectJAnnotation<?> aspectJAnnotation =
    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    // 没有注解那肯定忽略
    if (aspectJAnnotation == null) {
        return null;
    }

    // 得到一个AspectJExpressionPointcut对象
    AspectJExpressionPointcut ajexp =
    new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
    ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    if (this.beanFactory != null) {
        ajexp.setBeanFactory(this.beanFactory);
    }
    return ajexp;
}

2.1.2.1.1. 获取AspectJAnnotation实例

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

private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
		A result = AnnotationUtils.findAnnotation(method, toLookFor);
		if (result != null) {
			// 内部会去解析
			return new AspectJAnnotation<>(result);
		}
		else {
			return null;
		}
	}

public AspectJAnnotation(A annotation) {
			this.annotation = annotation;
			this.annotationType = determineAnnotationType(annotation);
			try {
				this.pointcutExpression = resolveExpression(annotation);
				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);
			}
		}

//通过注解实例,获取到了注解类型和切点表达式
		private AspectJAnnotationType determineAnnotationType(A annotation) {
			AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType());
			if (type != null) {
				return type;
			}
			throw new IllegalStateException("Unknown annotation type: " + annotation);
		}


private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap = new HashMap<>(8);

		static {
			annotationTypeMap.put(Pointcut.class, AspectJAnnotationType.AtPointcut);
			annotationTypeMap.put(Around.class, AspectJAnnotationType.AtAround);
			annotationTypeMap.put(Before.class, AspectJAnnotationType.AtBefore);
			annotationTypeMap.put(After.class, AspectJAnnotationType.AtAfter);
			annotationTypeMap.put(AfterReturning.class, AspectJAnnotationType.AtAfterReturning);
			annotationTypeMap.put(AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing);
		}

private String resolveExpression(A annotation) {
			for (String attributeName : EXPRESSION_ATTRIBUTES) {
				Object val = AnnotationUtils.getValue(annotation, attributeName);
				if (val instanceof String) {
					String str = (String) val;
					if (!str.isEmpty()) {
						return str;
					}
				}
			}
			throw new IllegalStateException("Failed to resolve expression: " + annotation);
		}

private static final String[] EXPRESSION_ATTRIBUTES = new String[] {"pointcut", "value"};

看代码可能有点头疼,奉上debug截图

2.1.2.1.2. 实例化AspectJExpressionPointcut(切点)对象

第一步拿到了AspectJAnnotation,然后到第二步实例化AspectJExpressionPointcut对象

// 得到一个AspectJExpressionPointcut对象
AspectJExpressionPointcut ajexp =
      new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());

public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
	 //切面类信息	
   this.pointcutDeclarationScope = declarationScope;
		if (paramNames.length != paramTypes.length) {
			throw new IllegalStateException(
					"Number of pointcut parameter names must match number of pointcut parameter types");
		}
   //参数信息
		this.pointcutParameterNames = paramNames;
   //参数类型
		this.pointcutParameterTypes = paramTypes;
	}

1、可以看到传入的三个参数中,有两个是空信息,然后调用了ajexp.setExpression(aspectJAnnotation.getPointcutExpression())就设置了切点表达式进去(expression=“pointCut()”),就这样切点的实例化结束了

2、目前只是拿到切点而已,可是我们需要进行切点匹配,有类级别和方法级别的匹配,看上去好像并不是在这里进行匹配的,那在哪里匹配呢?我们看下他的继承关系

AspectJExpressionPointcut的继承关系 

由图可得,它实现Pointcut接口,而且实现了ClassFilterMethodMathcher接口。所以说这AspectJExpressionPointcut拥有类信息匹配和方法匹配的能力!!

我们进去看看他的方法

@Override
public ClassFilter getClassFilter() {
    obtainPointcutExpression();
    return this;
}

@Override
public MethodMatcher getMethodMatcher() {
    obtainPointcutExpression();
    return this;
}

可以看到这两个方法被重写了,而obtainPointcutExpression()这个方法的作用是什么?因为前面只是拿到了切点表达式信息而已,如本文的(expression=“pointCut()”),那么这里就是匹配pointcut()里的execution配置的路径信息,这个方法就是干这个用的

进入obtainPointcutExpression()

private PointcutExpression obtainPointcutExpression() {
    if (getExpression() == null) {
        throw new IllegalStateException("Must set property 'expression' before attempting to match");
    }
    if (this.pointcutExpression == null) {
        // 获取类加载器
        this.pointcutClassLoader = determinePointcutClassLoader();
        // 获取切点表达式信息
        this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
    }
    return this.pointcutExpression;
}
private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
    PointcutParser parser = initializePointcutParser(classLoader);
    PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
    for (int i = 0; i < pointcutParameters.length; i++) {
        pointcutParameters[i] = parser.createPointcutParameter(
            this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
    }
    //解析切点表达式
    return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
                                          this.pointcutDeclarationScope, pointcutParameters);
}


public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
    PointcutExpressionImpl pcExpr = null;
    try {
        //获取到advice的配置的value的值,如本文的pointcut()
        Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
        //这里是根据pointcut() 获取到execution配置信息
        pc = concretizePointcutExpression(pc, inScope, formalParameters);
        validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
        pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
    } catch (ParserException pEx) {
        throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
    } catch (ReflectionWorld.ReflectionWorldException rwEx) {
        throw new IllegalArgumentException(rwEx.getMessage());
    }
    return pcExpr;
}

2.1.2.2. new InstantiationModelAwarePointcutAdvisorImpl

经过上面一系列操作,切点实例被创建出来了,而且还重写了getClassFilter()和getMethodMatcher(),可是还不能直接使用,需要解析pointcutExpression里的execution路径,并才能进行类/方法匹配。

还记得前面说的Advisor里会实例化advice吗,我们看一下

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
                                                  Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
                                                  MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    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
        // AspectJExpressionPointcut declaredPointcut
        this.pointcut = this.declaredPointcut;
        this.lazy = false;
        // 通过切点和方法信息new一个Advice对象,提醒:当前是在Advisor内部了
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}

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


public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
		//获取我们的切面类的class对象
		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		//获取切面方法上的注解
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		//解析出来的注解信息是否为null
		if (aspectJAnnotation == null) {
			return null;
		}

		//判断这里的class对象是不是切面信息对象
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}
		// 记录找到了advice方法
		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		AbstractAspectJAdvice springAdvice;

		// 按不同的注解类型得到不同的Advice
		switch (aspectJAnnotation.getAnnotationType()) {
		//是PointCut注解 那么就抛出异常 因为在外面传递进来的方法已经排除了pointcut的方法
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			case AtAround:  // @Around 环绕通知 构建AspectJAroundAdvice
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtBefore:  //前置通知  构建AspectJMethodBeforeAdvice
				springAdvice = new AspectJMethodBeforeAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfter:  //后置通知 AspectJAfterAdvice
				springAdvice = new AspectJAfterAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfterReturning: //返回通知 AspectJAfterReturningAdvice
				springAdvice = new AspectJAfterReturningAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:  //异常通知   AspectJAfterThrowingAdvice
				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);
		}

		//配置我们构建出来的通知对象
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();

		return springAdvice;
	}

上面代码说简单点就是,在Advisor构造函数里实例化了advice,并把传入的切点实例做参数,一起生成Advisor实例

2.2. AbstractAdvisorAutoProxyCreator

在段落 2.1中,我们拿到了所有的advisors,然后需要这些advisors进行过滤,看看哪些advisors属于这个bean的

由此来到了粉色区域(AbstractAutoProxyCreator类)里,我们先大概浏览一下流程图,心里有个数先

由图可知,里面有类信息/方法信息匹配,一看就是前面段落 2.1 重写的那两个方法的功劳

进代码看看

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

    // 寻找匹配的Advisor
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 找到所有的Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 进行筛选,判断我们的通知能不能作用到当前的类上(切点是否命中当前Bean)
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

		extendAdvisors(eligibleAdvisors);

		// 对Advisor进行排序,按Ordered接口、@Order注解进行排序
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}


/**
	 * 判断我们候选的通知能否作用到我们当前正在创建的类上
	 * @param candidateAdvisors 候选的增强器
	 * @param beanClass 正在创建的bean的class对象
	 * @param beanName  beanName
	 * @return 返回合适本类的通知器
	 * @see ProxyCreationContext#getCurrentProxiedBeanName()
	 */
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
		//用来记录当前正在创建的被代理对象的名称
		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			/**
			 * 从候选的通知器中找到当前Bean关联的advisors
			 */
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			//从线程局部变量中清楚当前正在创建的beanName的代理对象名称
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}


public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		// 如果没有通知 肯定 直接返回
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		//定义一个匹配到的增强器集合对象
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		//循环我们候选的增强器对象
		for (Advisor candidate : candidateAdvisors) {
			//判断我们的增强器对象是不是实现了IntroductionAdvisor 
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		//不为空
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			//判断我们的增强器对象是不是实现了IntroductionAdvisor 
			if (candidate instanceof IntroductionAdvisor) {
				//在上面已经处理过 ,不需要处理
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		//引介增强的匹配
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		 //PointcutAdvisor 类型的匹配,Spring AOP 生成的advisor,通过这种类型匹配
        else if (advisor instanceof PointcutAdvisor) {
			//转为PointcutAdvisor类型
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			//找到真正能用的增强器
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}


public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		/**
		 * 判断targetClass是不是和当前Pointcut匹配
		 * 进行类级别过滤(通过AspectJ)
		 */
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}
		/**
		 * 进行方法级别过滤
		 */
		//如果pc.getMethodMatcher()返回TrueMethodMatcher则匹配所有方法
		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		//判断匹配器是不是IntroductionAwareMethodMatcher  只有AspectJExpressionPointCut才会实现这个接口
		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		//创建一个集合用于保存targetClass 的class对象
		Set<Class<?>> classes = new LinkedHashSet<>();
		//判断当前class是不是代理的class对象
		if (!Proxy.isProxyClass(targetClass)) {
			//加入到集合中去
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		//获取到targetClass所实现的接口的class对象,然后加入到集合中
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		//循环所有的class对象
		for (Class<?> clazz : classes) {
			//通过class获取到所有的方法
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			//循环我们的方法
			for (Method method : methods) {
				//通过methodMatcher.matches来匹配我们的方法
				if (introductionAwareMethodMatcher != null ?
						// 通过切点表达式进行匹配 AspectJ方式
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						// 通过方法匹配器进行匹配 内置aop接口方式
						methodMatcher.matches(method, targetClass)) {
					// 只要有1个方法匹配上了就创建代理
					return true;
				}
			}
		}

		return false;
	}

在上面的代码中就知道了我们获得的一堆advisors是如何一个个跟bean匹配的。

2.3. AbstractAutoProxyCreator

在前面经过一系列骚操作,获取到符合当前bean的advisors了,接下来就轮到生成代理对象了,看下流程图清晰点

我们从getBean()的后置处理器banPostProcessor开始讲起

/**
 * AbstractAutoProxyCreator类
 * 正常进行AOP的地方
 */
@Override
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;
}

进入wrapIfNecessary()方法

因为第一步的specificInterceptors[]数组其实就是advisors,需要传到第二步的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.copyFrom(this);
    //为proxyFactory设置创建jdk代理还是cglib代理
    // 如果设置了 <aop:aspectj-autoproxy proxy-target-class="true"/>不会进if,说明强制使用cglib
    if (proxyFactory.isProxyTargetClass()) {
        if (Proxy.isProxyClass(beanClass)) {

            for (Class<?> ifc : beanClass.getInterfaces()) {
                proxyFactory.addInterface(ifc);
            }
        }
    }
    else {
        // 如果没有指定,那么则判断是不是应该进行cglib代理(判断BeanDefinition中是否指定了要用cglib)
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            // 是否进行jdk动态代理,如果当前beanClass实现了某个接口,那么则会使用JDK动态代理
            evaluateProxyInterfaces(beanClass, proxyFactory);// 判断beanClass有没有实现接口
        }
    }

    // 将commonInterceptors和specificInterceptors整合再一起
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 在这一步会去判断advisors中是否存在IntroductionAdvisor,如果存在则会把对应的interface添加到proxyFactory中去
    proxyFactory.addAdvisors(advisors);    // 向ProxyFactory中添加advisor
    proxyFactory.setTargetSource(targetSource);   // 被代理的对象
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    // 代表之前是否筛选advise.
    // 因为继承了AbstractAdvisorAutoProxyCreator , 并且之前调用了findEligibleAdvisors进行筛选, 所以是true
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    ClassLoader classLoader = getProxyClassLoader();
    if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
        classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
    }
    // 生成代理对象
    return proxyFactory.getProxy(classLoader);
}


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

可以看到createAopProxy().getProxy(classLoader)有两种代理模式,cglibjdk代理

我们先看下ProxyFactory类的继承关系

createAopProxy()是ProxyCreatorSupport类实现的,也就是说ProxyFactory实际上把工作给到了他爸ProxyCreatorSupport去做

//ProxyCreatorSupport类
protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   // 默认为DefaultAopProxyFactory
   return getAopProxyFactory().createAopProxy(this);
}

进入DefaultAopProxyFactory类

/**
 *
 * @param config 用来为我们指定我们advisor信息
 * 该方法用来创建我们的代理对象
 * 我们的targetClass对象实现了接口,且  ProxyTargetClass 没有指定强制的走cglib代理,那么就是创建jdk代理
 * 我们代理的类没有实现接口,那么会直接走cglib代理
 * 若我们   ProxyTargetClass 指定为false 且代理类是接口才会走jdk代理 否在我们还是cglib代理
 * @return
 * @throws AopConfigException
 */
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 如果ProxyFactory的isOptimize为true,Spring认为cglib比jdk动态代理要快
    // 或者isProxyTargetClass为true,
    // 或者被代理对象没有实现接口,
    // 或者只实现了SpringProxy这个接口
    // 那么则利用Cglib进行动态代理,但如果被代理类是接口,或者被代理类已经是进行过JDK动态代理而生成的代理类了则只能进行JDK动态代理

    // 其他情况都会进行JDK动态代理,比如被代理类实现了除SpringProxy接口之外的其他接口

    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.");
        }
        //targetClass是接口 使用的就是jdk代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        //cglib代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        //动态代理
        return new JdkDynamicAopProxy(config);
    }
}

这里就很清晰了,创建对象的任务交给jdk或者cglib去做,下篇文章再详细讲解创建代理对象的过程了

最后:作为图灵学院一份子,学习来源于周瑜和徐庶两位我特别敬重的老师,站在巨人的肩膀上增加了自己的理解,本文不以商业化为目的,纯个人学习使用

参考文献:

Spring AOP 第二篇-Spring 如何解析切面获取切点,通知和生成代理对象_spring怎么判断要走切面_Cison chen的博客-CSDN博客

Spring Aop之Advisor解析

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。