前言
依赖注入完成之后,初始化方法会调用各个后置处理器的postProcessAfterInitialization()方法,当为CommonAnnotationBeanPostProcessor的时候,会实现@PostConstruct 标记的方法。
引入aspect jar包之后,会多出一个后置处理器AnnotationAwareAspectJAutoProxyCreator,说明aop的实现逻辑在此后置处理器的postProcessAfterInitialization()方法中。
论述
AbstractAutoProxyCreator->postProcessAfterInitialization():
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
AbstractAutoProxyCreator->wrapIfNecessary():
// 如果有的话,就创建代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
AbstractAdvisorAutoProxyCreator->getAdvicesAndAdvisorsForBean():
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
AbstractAdvisorAutoProxyCreator->findEligibleAdvisors():
// 找切面方法,已在上篇分析过
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 解析切面方法,然后遍历bean方法,看是否符合切面表达式
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
..........
return eligibleAdvisors;
AbstractAdvisorAutoProxyCreator->findAdvisorsThatCanApply():
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
AopUtils->findAdvisorsThatCanApply():
for (Advisor candidate : candidateAdvisors) {
// 如果为true的话,就将该切面方法添加到eligibleAdvisors集合
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
AopUtils->canApply():
// advisor一般是PointcutAdvisor的子类
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
此篇仅讲述解析切面方法的部分,下面以@Around("doCut()") public int doAround()方法为例
AopUtils->canApply():
// 这里matches方法一般都返回true,但是getClassFilter第一次调用时,会解析切面方法
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
......
// 遍历切面方法candidateAdvisors的过程中,pc.getClassFilter()在一系列调用栈之后,会走到这里
PointcutParser->parsePointcutExpression():
// expression是注解值,inScope是aop类
Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
PointcutParser->resolvePointcutExpression():
PatternParser parser = new PatternParser(expression);
parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
// 此处返回ReferencePointcut对象
Pointcut pc = parser.parsePointcut();
validateAgainstSupportedPrimitives(pc, expression);
IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters);
// 解析切入点doCut()
pc = pc.resolve(resolutionScope);
return pc;
Pointcut->resolve():
this.resolveBindings(bindingResolutionScope, bindingTable);
ReferencePointcut->resolveBindings():
// 根据所给name寻找是否有符合其名称的切点方法
ResolvedPointcutDefinition pointcutDef = searchType.findPointcut(name); // --1
// 没有找到切点方法,会尝试从外部类寻找
......
// 若外部类也没找到的话,就会报错了
if (pointcutDef == null) {
scope.message(IMessage.ERROR, this, "can't find referenced pointcut " + name);
return;
}
ResolvedType->findPointcut() // --1
for (Iterator<ResolvedMember> i = getPointcuts(); i.hasNext();) {
ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next();
if (f != null && name.equals(f.getName())) {
// 如果方法名和注解中的值一样的话,就返回,否则继续寻找
return f;
}
}
// i.hasNext()先在所给aop类中找寻切点方法,然后从其父类中寻找
......
// 一系列调用栈之后,会走到这里
Java15ReflectionBasedReferenceTypeDelegate->getDeclaredPointcuts():
// 获取带有@PointCut注解的方法,封装成PointCut对象
Pointcut[] pcs = this.myType.getDeclaredPointcuts();
......
// 得到注解值并解析
String pcExpr = pcs[i].getPointcutExpression().toString();
org.aspectj.weaver.patterns.Pointcut pc = parser.resolvePointcutExpression(pcExpr, getBaseClass(), parameters[i]);
AjTypeImpl->getDeclaredPointcuts():
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// asPointcut()方法会查方法中是否有@Pointcut注解,有则返回Pointcut对象实例,否则返回空
Pointcut pc = asPointcut(method);
if (pc != null) pointcuts.add(pc);
}
在Java15ReflectionBasedReferenceTypeDelegate->getDeclaredPointcuts()方法中,得到Pointcut对象数组后,会对表达式进行解析,继续调用Pointcut->resolvePointcutExpression()方法,parser.parsePointcut()方法根据表达式返回不同类型的Pointcut,@annotation表达式返回AnnotationPointcut对象,之后pc.resolve(resolutionScope)也不相同
分支2中通过
this.myType.getDeclaredPointcuts()方法得到的Pointcut对象数组构成
总结
在找到切面方法之后,会对每一个切面方法解析和验证,该过程只进行一次(从AspectJExpressionPointcut->buildPointcutExpression()方法开始)
@Around("doCut()"):解析doCut()表达式,得知是一个方法,从OperationAop类寻找带有@Pointcut注解的方法@Pointcut("@annotation(com.hx.anno.HodayDouble)"):解析@annotation(com.hx.anno.HodayDouble)表达式,得知是一个注解,验证是否有HodayDouble这个注解- 验证带有
@Pointcut注解方法名是否叫doCut(),如果是,返回,如果不是,从OperationAop父类寻找带有@Pointcut注解的方法,重复步骤2-3 - 如果没有的话,从OperationAop外部类寻找带有
@Pointcut注解的方法,重复步骤2-4 - 结束,验证成功继续进行,验证失败抛出异常