Spring-AOP模块的Advisor分析
描述:Advisor模块是切面核心实现,需要重点掌握
使用结构:
UML结构图如下:
备注:IntroductionAdvisor:不使用pointcut,只作用于类(根据类的实现接口做筛选)。 todo:详细理解IntroductionAdvisor
PointcutAdvisor的UML结构图如下:
Pointcut: 一个切入点由一个类过滤器和一个方法匹配器组成; 维度是类和方法
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter(); //类过滤器
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher(); //方法匹配器
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
实现类型 | 实现功能 | 例子 |
---|---|---|
JdkRegexpMethodPointcut | 使用正则表达式来匹配类型和方法 | |
AnnotationMatchingPointcut | 通过类和方法是否实现特定注解进行匹配 | |
AbstractExpressionPointcut | 使用表达式进行方法匹配 | |
AspectJExpressionPointcut | 使用AspectJweaver来计算切入点表达式(pointcut expression),支持方法(Method) |
AbstractExpressionPointcut类UML结构图如下:
AspectJExpressionPointcut:使用AspectJweaver来计算切入点表达式(pointcut expression),支持方法(Method)
核心方法:
1.matches
matches方法核心业务流程:
@Override
public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
obtainPointcutExpression();
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
// Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
// consistent with return of MethodInvocationProceedingJoinPoint
ProxyMethodInvocation pmi = null;
Object targetObject = null;
Object thisObject = null;
try {
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
targetObject = mi.getThis();
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
pmi = (ProxyMethodInvocation) mi;
thisObject = pmi.getProxy();
}
catch (IllegalStateException ex) {
// No current invocation...
if (logger.isDebugEnabled()) {
logger.debug("Could not access current invocation - matching with limited context: " + ex);
}
}
try {
JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
/*
* Do a final check to see if any this(TYPE) kind of residue match. For
* this purpose, we use the original method's (proxy method's) shadow to
* ensure that 'this' is correctly checked against. Without this check,
* we get incorrect match on this(TYPE) where TYPE matches the target
* type but not 'this' (as would be the case of JDK dynamic proxies).
* <p>See SPR-2979 for the original bug.
*/
if (pmi != null && thisObject != null) { // there is a current invocation
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
return false;
}
if (joinPointMatch.matches()) {
bindParameters(pmi, joinPointMatch);
}
}
return joinPointMatch.matches();
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
" - falling back to non-match", ex);
}
return false;
}
}
2.obtainPointcutExpression
3.getShadowMatch
AbstractBeanFactoryPointcutAdvisor:基于BeanFactory的抽象PointcutAdvisor,通过名称来引用BeanFactory中的Spring Bean 作为Advice(Spring AOP和IOC模块集成)
类图如下:
核心方法:
1.resetAdviceMonitor
2.getAdvice
DefaultAdvisorChainFactory:根据Advised对象的advisor列表重新生成MethodInterceptor chain
核心方法:
1.getInterceptorsAndDynamicInterceptionAdvice
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
执行流程如下:
遍历config对象的Advisor列表类型,采取不同的过滤方式:
1.Advisor的具体实现类型是PointcutAdvisor,通过class和method match 进行过滤
2.Advisor的具体实现类型是IntroductionAdvisor,通过class match进行过滤
3.其他类型直接通过
ReflectiveAspectJAdvisorFactory:用于创建AspectJ类型的Spring AOP advisor的工厂类;在使用AspectJ 5注解的类型上,通过反射的方式调用相应的advice方法
核心方法:
-
getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory)
执行流程:
a.遍历使用AspectJ注解对象的包含Around,Before,After,AfterReturning和AfterThrowing注解的方法,调用getAdvisor方法来生 成Advisor
b.判断当前类型的Aspect注解设置的延迟初始化属性,决定是否生成SyntheticInstantiationAdvisor
c.遍历当前类型的使用DeclareParents注解的字段,生成DeclareParentsAdvisor
2. getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName)
执行流程:
3. getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName)
执行流程:
根据方法上的Aspect注解,生成对应的Advice
注解类型 | advice类型 | 分析链接 |
---|---|---|
AtBefore |
AspectJMethodBeforeAdvice |
|
AtAfter |
AspectJAfterAdvice |
|
AtAfterReturning |
AspectJAfterReturningAdvice |
|
AtAfterThrowing |
AspectJAfterThrowingAdvice |
|
AtAround |
AspectJAroundAdvice |