0%

AopUtils#canApply 方法匹配分析

问题描述

既然ReflectionUtils.getAllDeclaredMethods(Class<?> clazz)可以获取父类和接口继承的方法,是否有必要先调用ClassUtils.getAllInterfacesForClassAsSet(Class<?> clazz)可以获取定类(clazz)及其所有父类(包括超类)实现的所有接口,再次遍历接口获取方法?

源码分析

Advisor 排序规则

  1. Aspect Bean 顺序,根据 Bean 的 Order 注解或其它 Order 标识排序。
  2. Aspect 注解顺序 Around.class,Before.class,After.class,AfterReturning.class,AfterThrowing.class。
  3. 方法名称。

注意事项

Spring AOP Advice 场景

  1. 环绕通知(Interception Around Advice)
    1. public interface MethodInterceptor extends Interceptor
  2. 前置通知(Before Advice)
    1. public interface MethodBeforeAdvice extends BeforeAdvice
  3. 后置通知(After Advice)
    1. public interface AfterAdvice extends Advice
  4. 返回通知(After Returning Advice)
    1. public interface AfterReturningAdvice extends AfterAdvice
  5. 异常通知(Throws Advice)
    1. public interface ThrowsAdvice extends AfterAdvice
  6. 引入通知(Introduction Advice)
    1. public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport implements IntroductionInterceptor
    2. public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice
    3. 引入通知的主要作用是可以让生成的代理类实现额外的接口。

Spring AOP 使用关键接口

  • PointcutAdvisor = Advice + Pointcut
  • Advice: AspectJAroundAdvice/AspectJMethodBeforeAdvice/AspectJAfterAdvice/AspectJAfterReturningAdvice/AspectJAfterThrowingAdvice
  • Pointcut: AspectJExpressionPointcut
  • PointcutAdvisor: InstantiationModelAwarePointcutAdvisorImpl instanceof PointcutAdvisor
  • Advisor refers to PointcutAdvisor

Advisor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// org.springframework.aop.Advisor
public interface Advisor {
	Advice getAdvice();
	boolean isPerInstance();
}

// org.springframework.aop.PointcutAdvisor
public interface PointcutAdvisor extends Advisor {
	Pointcut getPointcut();
}

// org.springframework.aop.aspectj.InstantiationModelAwarePointcutAdvisor
public interface InstantiationModelAwarePointcutAdvisor extends PointcutAdvisor {}

// org.springframework.aop.IntroductionAdvisor
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
	ClassFilter getClassFilter();
	void validateInterfaces() throws IllegalArgumentException;    
}

// org.springframework.aop.IntroductionInfo
public interface IntroductionInfo {
	Class<?>[] getInterfaces();
}

Advice

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// org.aopalliance.aop.Advice
public interface Advice {}

// org.springframework.aop.BeforeAdvice
public interface BeforeAdvice extends Advice {}

// org.springframework.aop.MethodBeforeAdvice
public interface MethodBeforeAdvice extends BeforeAdvice {}

// org.springframework.aop.AfterAdvice
public interface AfterAdvice extends Advice {}

// org.springframework.aop.AfterReturningAdvice
public interface AfterReturningAdvice extends AfterAdvice {}

// org.springframework.aop.ThrowsAdvice
public interface ThrowsAdvice extends AfterAdvice {}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// org.aopalliance.intercept.Interceptor
public interface Interceptor extends Advice {}

// org.aopalliance.intercept.MethodInterceptor
public interface MethodInterceptor extends Interceptor {}

// org.springframework.aop.DynamicIntroductionAdvice
public interface DynamicIntroductionAdvice extends Advice {}

// org.springframework.aop.IntroductionInterceptor
public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {}

// org.aopalliance.intercept.ConstructorInterceptor
public interface ConstructorInterceptor extends Interceptor {}

Pointcut

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// org.springframework.aop.Pointcut
public interface Pointcut {
	ClassFilter getClassFilter();
	MethodMatcher getMethodMatcher();
}

// org.springframework.aop.ClassFilter
public interface ClassFilter {
	boolean matches(Class<?> clazz);
}

// org.springframework.aop.MethodMatcher
public interface MethodMatcher {
	/**
	 * Perform static checking whether the given method matches.
	 * <p>If this returns {@code false} or if the {@link #isRuntime()}
	 * method returns {@code false}, no runtime check (i.e. no
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
	 * will be made.
	 */    
	boolean matches(Method method, Class<?> targetClass);
	/**
	 * Is this MethodMatcher dynamic, that is, must a final call be made on the
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
	 * runtime even if the 2-arg matches method returns {@code true}?
	 * <p>Can be invoked when an AOP proxy is created, and need not be invoked
	 * again before each method invocation,
	 * @return whether a runtime match via the 3-arg
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method
	 * is required if static matching passed
	 */    
	boolean isRuntime();
	/**
	 * Check whether there a runtime (dynamic) match for this method,
	 * which must have matched statically.
	 * <p>This method is invoked only if the 2-arg matches method returns
	 * {@code true} for the given method and target class, and if the
	 * {@link #isRuntime()} method returns {@code true}. Invoked
	 * immediately before potential running of the advice, after any
	 * advice earlier in the advice chain has run.
     */
	boolean matches(Method method, Class<?> targetClass, Object... args);
}

END

前置知识

Java JDK 动态代理使用方法,Java CGLIB 动态代理动态

Spring 代理与 Advisor

Spring JDK 动态代理

JdkDynamicAopProxy 是 InvocationHandler 的实现类,其 invoke 方法从 Spring 容器中获取所有匹配的 Spring AOP advisor,将其转换为 Interceptor。