普通增强器的获取逻辑通过getAdvisor方法实现,实现步骤包括对切点的注解的获取及根据注解信息生成增强。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName)
{
validate(aif.getAspectMetadata().getAspectClass());
//切点信息的获取
AspectJExpressionPointcut ajexp = getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
if(ajexp == null)
return null;
else
//根据切点信息生成增强器
return new InstantiationModelAwarePointcutAdvisorImpl(this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}
(1)切点信息的获取。所谓获取切点信息就是指定注解的表达式信息的获取,如@Before("test()")
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class candidateAspectClass)
{
//获取方法上的注解
AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if(aspectJAnnotation == null)
{
return null;
} else
{
//使用AspectJExpressionPointcut实例封装获取的信息
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
//提取得到的注解中的表达式如:@Pointcut("execution(* *.*test*(..))")中的execution(* *.*test*(..))<pre name="code" class="java">
))
ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); return ajexp; } }
protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method)
{
//设置敏感的注解类
Class classesToLookFor[] = {
org/aspectj/lang/annotation/Before, org/aspectj/lang/annotation/Around, org/aspectj/lang/annotation/After, org/aspectj/lang/annotation/AfterReturning, org/aspectj/lang/annotation/AfterThrowing, org/aspectj/lang/annotation/Pointcut
};
for(Class<? extends Annotation> c : classsesToLookFor)
{
AspectJAnnotation foundAnnotation = findAnnotation(method, c);
if(foundAnnotation != null)
return foundAnnotation;
}
return null;
}
//获取指定方法上的注解并使用AspectJAnnotation封装
private static AspectJAnnotation findAnnotation(Method method, Class toLookFor)
{
Annotation result = AnnotationUtils.findAnnotation(method, toLookFor);
if(result != null)
return new AspectJAnnotation(result);
else
return null;
}
(2)根据切点信息生成增强。所有的增强都有Advisor实现类InstantiationModelAwarePontcutAdvisorImpl统一疯长。
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName)
{
declaredPointcut = ajexp;
this.method = method;
atAspectJAdvisorFactory = af;
aspectInstanceFactory = aif;
declarationOrder = declarationOrderInAspect;
this.aspectName = aspectName;
if(aif.getAspectMetadata().isLazilyInstantiated())
{
Pointcut preInstantiationPointcut = Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), declaredPointcut);
pointcut = new PerTargetInstantiationModelPointcut(declaredPointcut, preInstantiationPointcut, aif);
lazy = true;
} else
{
instantiatedAdvice = instantiateAdvice(declaredPointcut);
pointcut = declaredPointcut;
lazy = false;
}
}
封装过程只是简单地将信息封装在类的实例中,所有的额信息单纯地复制。在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如@Before(“test()”)与After(“test()”)标签的不同就是增强器增强的位置不同,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的额增强器就是在instantiateAdvice函数中实现的。
private Advice instantiateAdvice(AspectJExpressionPointcut pcut)
{
return atAspectJAdvisorFactory.getAdvice(method, pcut, aspectInstanceFactory, declarationOrder, aspectName);
}
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName)
{
Class candidateAspectClass = aif.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if(aspectJAnnotation == null)
return null;
//if we get here,we know we have an AspectJ method. Check that its an AspectJ-annotated class
if(!isAspect(candidateAspectClass))
throw new AopConfigException((new StringBuilder()).append("Advice must be declared inside an aspect type: Offending method '").append(candidateAdviceMethod).append("' in class [").append(candidateAspectClass.getName()).append("]").toString());
if(logger.isDebugEnabled())
logger.debug((new StringBuilder()).append("Found AspectJ method: ").append(candidateAdviceMethod).toString());
AbstractAspectJAdvice springAdvice;
switch(_cls4..SwitchMap.org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotationType[aspectJAnnotation.getAnnotationType().ordinal()])
{
case 1: // '\001'
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
break;
case 2: // '\002'
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
break;
case 3: // '\003'
springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
AfterReturning afterReturningAnnotation = (AfterReturning)aspectJAnnotation.getAnnotation();
if(StringUtils.hasText(afterReturningAnnotation.returning()))
springAdvice.setReturningName(afterReturningAnnotation.returning());
break;
case 4: // '\004'
springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
AfterThrowing afterThrowingAnnotation = (AfterThrowing)aspectJAnnotation.getAnnotation();
if(StringUtils.hasText(afterThrowingAnnotation.throwing()))
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
break;
case 5: // '\005'
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
break;
case 6: // '\006'
if(logger.isDebugEnabled())
logger.debug((new StringBuilder()).append("Processing pointcut '").append(candidateAdviceMethod.getName()).append("'").toString());
return null;
default:
throw new UnsupportedOperationException((new StringBuilder()).append("Unsupported advice type on method ").append(candidateAdviceMethod).toString());
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrderInAspect);
String argNames[] = parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if(argNames != null)
springAdvice.setArgumentNamesFromStringArray(argNames);
springAdvice.calculateArgumentBindings();
return springAdvice;
}
}
从函数中可以看到,Spring会根据不同的注解生成不同的增强器,例如AtBefore会对应AspectJMethodBeforeAdvice。
2.增加同步实例化增强器
如果寻找的增强器不为空而且又配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器。同步实例化增强器SyntheticInstantiationAdvisor,如下:
protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor
{
public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif)
{
super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {
//目前方法前调用,类似@Before
public void before(Method method, Object args[], Object target)
{ //简单初始化aspect
aif.getAspectInstance();
}
3.获取DeclareParents注解
DeclareParents主要用于引介增强的注解形式的实现,而其实现方式驭普通增强很类似,只不过使用DeclareParentsAdvisor对功能进行封装。
private Advisor getDeclareParentsAdvisor(Field introductionField)
{
DeclareParents declareParents = (DeclareParents)introductionField.getAnnotation(org/aspectj/lang/annotation/DeclareParents);
if(declareParents == null)
return null;
if(org/aspectj/lang/annotation/DeclareParents.equals(declareParents.defaultImpl()))
throw new IllegalStateException("defaultImpl must be set on DeclareParents");
else
return new DeclareParentsAdvisor(introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}
后面一节我们一起分析一下,Spring如何寻找匹配的增强器,篇幅较长,也比较复杂,但还是希望我们一起看下去,因为这个过程虽然很艰辛,坚持过后,你会发现,收获是非常巨大的。