切面配对解析

系列文章目录

切点匹配解析
Advisor与@Aspect解析
getPointcut解析
Advisor解析



前言

springAOP中wrapIfNecessary()方法可以获取所有的切面集合,然后根据当前传入bean对象对切面进行配对,配对过程则是通过findAdvisorsThatCanApply()方法实现

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 获取候选Advisors对象(解析advisors实例)
    List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
    // 从所有advisor中,筛选出跟当前bean匹配的advisor
    List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    this.extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
    }

    return eligibleAdvisors;
}

findAdvisorsThatCanApply

findAdvisorsThatCanApply中主要通过AopUtils.findAdvisorsThatCanApply()方法进行切面配对

protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);

    List var4;
    try {
        var4 = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    } finally {
        ProxyCreationContext.setCurrentProxiedBeanName((String)null);
    }

    return var4;
}

findAdvisorsThatCanApply()主要流程:
1.遍历所有切面对象
2.canApply()方法验证当前切面对象是否能和目标bean类进行匹配

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    } else {
        List<Advisor> eligibleAdvisors = new ArrayList();
        Iterator var3 = candidateAdvisors.iterator();
		// 暂时忽略
        while(var3.hasNext()) {
            Advisor candidate = (Advisor)var3.next();
            if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                eligibleAdvisors.add(candidate);
            }
        }
		
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        // 遍历切面集合
        Iterator var7 = candidateAdvisors.iterator();

        while(var7.hasNext()) {
            Advisor candidate = (Advisor)var7.next();
            // 验证是否可以匹配
            if (!(candidate instanceof IntroductionAdvisor) && canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }
}

canApply()

主要配对过程就是通过canApply方法实现:首先将advisor对象强转为PointcutAdvisor接口类型(多态)
这里的advisor对象实际类型为InstantiationModelAwarePointcutAdvisorImpl类型
在这里插入图片描述
具体原因在切面获取解析中有讲;InstantiationModelAwarePointcutAdvisorImpl实现了PointcutAdvisor接口故可以进行转化
pca.getPointcut()获取InstantiationModelAwarePointcutAdvisorImpl对象中declaredPointcut成员,而它的实际类型为AspectJExpressionPointcut类

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor)advisor).getClassFilter().matches(targetClass);
    } else if (advisor instanceof PointcutAdvisor) {
    	// 主要配对流程
        PointcutAdvisor pca = (PointcutAdvisor)advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    } else {
        return true;
    }
}

上述描述传递第一个参数实际为AspectJExpressionPointcut类型,而该类实现Pointcut接口以及MethodMatcher接口与ClassFilter接口
根据接口名可以得知MethodMatcher接口实现方法的匹配而ClassFilter接口实现类的匹配功能
在这里插入图片描述
canApply流程:
1.验证当前切面目标类是否对应bean对象所属类
2.验证当前是否能够匹配一切方法 若能直接返回true
3.添加当前目标类以及其接口类到classes中
4.遍历classes并通过反射获取方法集合验证各个方法是否能匹配上目标类

注意:
1.添加类时单独添加了目标类其各个接口类,因为springAOP是可以对抽象类或接口进行增强,若抽象类中存在未实现的接口则单纯通过反射无法直接获取,所以需要添加其各个接口类.
2.根据增强的动态性与静态性匹配方式会有所不同(带参数增强或默认全增强).

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    // 类匹配
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    } else {
    	// 方法匹配
        MethodMatcher methodMatcher = pc.getMethodMatcher();
        // 是否匹配一切方法
        if (methodMatcher == MethodMatcher.TRUE) {
            return true;
        } else {
            IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
            if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
                introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher)methodMatcher;
            }

            Set<Class<?>> classes = new LinkedHashSet();
            // 若目标类非代理类则将其原始类添加到classes中
            if (!Proxy.isProxyClass(targetClass)) {
                classes.add(ClassUtils.getUserClass(targetClass));
            }
			//将目标类实现的所有接口类(包括未实现 Chat-gpt)也添加到classes中
            classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
            Iterator var6 = classes.iterator();

            while(var6.hasNext()) {
                Class<?> clazz = (Class)var6.next();
                // 通过反射获取当前遍历类的方法集合
                Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
                Method[] var9 = methods;
                int var10 = methods.length;

                for(int var11 = 0; var11 < var10; ++var11) {
                    Method method = var9[var11];
                    // 是否进行动态匹配 (带参数)
                    if (introductionAwareMethodMatcher != null) {
                        if (introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) {
                            return true;
                        }
                    // 非动态匹配 (不带参数)
                    } else if (methodMatcher.matches(method, targetClass)) {
                        return true;
                    }
                }
            }

            return false;
        }
    }
}

总结

切面匹配的核心就是通过canApply()方法实现:
1.根据切点表达式定位类与方法
2.获取目标类及其接口类的方法
3.匹配定位方法与目标方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值