getPointcut()过程解析

系列文章目录

切点匹配解析
Advisor与@Aspect解析
Advisor获取解析



前言

springAOP获取切面对象这个过程中获取了切点对象pointcut,在Advisor获取解析中的getAdvisor()方法中通过调用getPointcut()方法得到切点对象


getPointcut()过程解析

参数:
Method candidateAdviceMethod: 目前匹配的方法对象(@aspect修饰类中的方法)
Class<?> candidateAspectClass:目前匹配的类对象(@aspect修饰的类)
返回值类型
AspectJExpressionPointcut 

可以看见AspectJExpressionPointcut类实现了Pointcut接口的同时也实现了ClassFilter与MethodMatcher接口(后续切点值匹配时起作用)
在这里插入图片描述
getPointcut()主要过程:
1.解析当前方法注解信息并获取切点表达式值
2.实例化切点对象并设置切点表达式

// 获得切点实例
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass){
    // 解析切点类信息与切点表达式信息 封装在AspectJAnnotation对象中
    AspectJAnnotation<?> aspectJAnnotation = findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null)
        return null;
    // 实例化切点
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
    pointcut.setExpression(aspectJAnnotation.getPointcutExpression());
    return pointcut;
}

可以看见获取切点所需要的主要信息是从findAspectJAnnotationOnMethod()方法中获得

findAspectJAnnotationOnMethod()

findAspectJAnnotationOnMethod()是SimulateAbstractAspectJAdvisorFactory类的成员方法(模拟AbstractAspectJAdvisorFactor类)

可以发现findAspectJAnnotationOnMethod()方法中出现:
AspectJAnnotation类以及ASPECTJ_ANNOTATION_CLASSES常量
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class[]{Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

ASPECTJ_ANNOTATION_CLASSES常量SimulateAbstractAspectJAdvisorFactory类所定义的常量类数组其值为各个修饰切点的注解类

在了解ASPECTJ_ANNOTATION_CLASSES信息后就可以清楚知道findAspectJAnnotationOnMethod()方法的功能:
遍历注解类数组通过findAnnotation()找到当前方法所对应的注解类,并将返回值封装为AspectJAnnotation<?>类型

@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
    Class[] var1 = ASPECTJ_ANNOTATION_CLASSES;
    int var2 = var1.length;

    for (int var3 = 0; var3 < var2; ++var3) {
        Class<?> clazz = var1[var3];
        AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
        if (foundAnnotation != null) {
            return foundAnnotation;
        }
    }
    return null;
}

若想明白AspectJAnnotation<?>类型究竟是什么还需要去探究findAnnotation()方法

findAnnotation()

<A extends Annotation> AspectJAnnotation<A>
泛型A需要实现Annotation接口
AnnotationUtils.findAnnotation(method, toLookFor)
匹配当前方法与当前注释 若成功则返回A类(该类实现Annotation接口 如Before.class...)

若匹配成功将AnnotationUtils.findAnnotation()的返回结果封装为AspectJAnnotation类的对象

@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
    A result = AnnotationUtils.findAnnotation(method, toLookFor);
    return result != null ? new AspectJAnnotation(result) : null;
}

AspectJAnnotation类

AspectJAnnotation类是在SimulateAbstractAspectJAdvisorFactory类中实现的静态内部类,,同时它还是一个泛型类;该类封装A annotation对象(实现Annotation接口即可)
通过其构造方法可以得知其主要功能:
1.封装获得的annotation对象(泛型)
2.通过determineAnnotationType方法获得其annotation类型
3.通过resolveExpression方法获得切点表达式
4.获取注解参数

protected static class AspectJAnnotation<A extends Annotation> {
    private static final String[] EXPRESSION_ATTRIBUTES = new String[]{"pointcut", "value"};
    private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap = new HashMap(8);
    private final A annotation;
    private final AspectJAnnotationType annotationType;
    private final String pointcutExpression;
    private final String argumentNames;

    public AspectJAnnotation(A annotation) {
        this.annotation = annotation;
        this.annotationType = this.determineAnnotationType(annotation);
        // 解析切点表达式
        try {
            this.pointcutExpression = this.resolveExpression(annotation);
            Object argNames = AnnotationUtils.getValue(annotation, "argNames");
            this.argumentNames = argNames instanceof String ? (String) argNames : "";
        } catch (Exception var3) {
            throw new IllegalArgumentException(annotation + " is not a valid AspectJ annotation", var3);
        }
    }
}

determineAnnotationType()

AspectJAnnotation类内部定义一个HashMap存储注解类与对应的枚举类AspectJAnnotationType
determineAnnotationType 方法则是根据传入的注解annotation获取其在HashMap中的对应value值并返回

private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap = new HashMap(8);
//HashMap赋值
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);
}
// 定义静态枚举类
protected static enum AspectJAnnotationType {
    AtPointcut,
    AtAround,
    AtBefore,
    AtAfter,
    AtAfterReturning,
    AtAfterThrowing;
    private AspectJAnnotationType() {
    }
}

private AspectJAnnotationType determineAnnotationType(A annotation) {
    AspectJAnnotationType type = (AspectJAnnotationType) annotationTypeMap.get(annotation.annotationType());
    if (type != null) {
        return type;
    } else {
        throw new IllegalStateException("Unknown annotation type: " + annotation);
    }
}

resolveExpression()

EXPRESSION_ATTRIBUTES 是AspectJAnnotation类定义的常量字符数组封装pointcut与value两个字符串,主要用于区别当前注解类是pointcut类型还是常规类型(@Before、@after…)
resolveExpression的主要过程:
通过AnnotationUtils.getValue找到当前annotation所对应的值并返回

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

private String resolveExpression(A annotation) {
    String[] var2 = EXPRESSION_ATTRIBUTES;
    int var3 = var2.length;

    for(int var4 = 0; var4 < var3; ++var4) {
        String attributeName = var2[var4];
        // 获取对应注解对象的pointcut值或value值(execution(* foo()))
        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);
}

总结

getPointcut()主要功能:
1.获取当前方法对应的注释信息并将其封装为AspectJAnnotation对象
2.实例化切点后利用封装好的信息对切点中信息进行赋值

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值