系列文章目录
切点匹配解析
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.匹配定位方法与目标方法