1. 前言
接着 Spring源码之事务(一)文章继续
2. 寻找事务类或方法对应的增强器
2.1. getAdvicesAndAdvisorsForBean()
Spring
通过 getAdvicesAndAdvisorsForBean()
获取指定 bean
对应的增强器,不但要找出增强器,而且还需要判断增强器是否满足要求
@Override
@Nullable
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();
}
寻找所有合适的增强器(增强器并不一定都适用于当前 bean
,要选出满足我们通配符的增强器)
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有的增强
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 寻找所有增强中适用于 bean 的增强并应用
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 在advice链的开始添加ExposeInvocationInterceptor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
上述方法的任务是:找出某个增强器是否适合于对应的类,而是否匹配的关键则在于是否从指定的类或类中的方法中找到对应的事务属性
2.2. 匹配增强器 findAdvisorsThatCanApply()
当找出所有的增强器后,接来的任务就是看这些增强器是否与 bean
(比如 ProductInfoServiceImpl
)对应的 class
匹配了,当然不只是 class
,class
内部的方法如果能够匹配也可以
/*寻找所有增强中适用于目标bean的增强并应用*/
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
/*设置当前要代理的beanName*/
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
/*过滤已经得到的advisors*/
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
/*清除标记*/
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
/*主要功能是寻找所有增强器中适用于当前class的增强器*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
// 保存筛选的合适增强器
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 首先处理引介增强
for (Advisor candidate : candidateAdvisors) {
// 核心匹配实现:canApply()
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// 引介增强已经处理
continue;
}
// 如果不是IntroductionAdvisor实例,对于普通的增强,调用canApply()重载方法
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
当前我们分析的是对于 ProductInfoServiceImpl
是否适用于此增强方法,那么当前的 advisor
就是之前查找出来的类型为 BeanFactoryTransactionAttributeSourceAdvisor
的 bean
实例。匹配合适的增强器核心步骤就是调用 canApply()
方法
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
// 如果增强是引介增强,那么直接获取切点表达式去匹配targetClass即可
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
// 如果属于PointcutAdvisor,继续调用重载方法
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
// 其余的默认为符合条件
else {
return true;
}
}
通过类的层次结构我们又知道:BeanFactoryTransactionAttributeSourceAdvisor
间接实现了 PointcutAdvisor
。因此,在 canApply()
函数中的第二个 if
判断时就会通过判断,将 BeanFactoryTransactionAttributeSourceAdvisor
中的 getPointcut()
方法返回值作为参数继续调用 canApply()
方法
那么继续跟踪 canApply()
方法,targetClass
参数为 ProductInfoServiceImpl
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;
}
// 然后继续寻找匹配类中哪个方法
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
// 如果是代理类,则需要返回原始类
if (!Proxy.isProxyClass(targetClass