先看一个使用 Spring AOP 代理的 Demo, 理解最初流程
public class ProxyFactoryDemo {
public static void main(String[] args) {
// 1. 构造目标对象
Cat catTarget = new Cat();
// 2. 通过 target 对象,构造 ProxyFactory 对象
ProxyFactory factory = new ProxyFactory(catTarget);
// 添加一个方法拦截器
factory.addAdvice(new MyMethodInterceptor());
// 3. 根据目标对象生成代理对象
Object proxy = factory.getProxy();
Animal cat = (Animal) proxy;
cat.eat();
}
// 增强处理逻辑
public static class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("MyMethodInterceptor invoke 调用 before invocation.proceed");
Object ret = invocation.proceed();
System.out.println("MyMethodInterceptor invoke 调用 after invocation.proceed");
return ret;
}
}
}
1. 实例化 ProxyFactory 对象 new ProxyFactory(catTarget)
的过程
// ProxyFactory.java
public ProxyFactory(Object target) {
setTarget(target); // 设置目标对象
setInterfaces(ClassUtils.getAllInterfaces(target)); // 设置目标对象实现的接口
}
2. 为 ProxyFactory 对象添加拦截器 factory.addAdvice(new MyMethodInterceptor());
的过程
首先,我们加入的 Advice 自己实现的 MyMethodInterceptor 对象,该对象继承了 MethodInterceptor
接口 。 MethodInterceptor 接口继承关系如下图:
接下来, 如下代码可以看出, addAdvice()
的动作做法是, 向内部的 List<Advisor>
集合中加入一个 DefaultPointcutAdvisor
对象. 是职责链模式的体现.
// ProxyFactory.java
private List<Advisor> advisors = new ArrayList<>();
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
this.advisors.add(pos, advisor);
}
-
(1)先来看 DefaultPointcutAdvisor 的继承体系
Advisor 接口
:持有Advice
对象的基础接口, 可将二者看做对等借口PointcutAdvisor 接口
:包含切入点 的 Advisor,从而可以针对符合Pointcut
规则的连接点进行增强处理Ordered 接口
:用来确定当前Advisor
在拦截器责任链列表中的位置,主要用在 Aspect 中
上面看到,PointcutAdvisor 持有 PointCut 接口
的引用。PointCut 接口
用来在代理时,判断被代理的对象和被代理的方法是否符合我们的要求, 该接口组合了 ClassFilter
接口和 MethodMatcher
接口。ClassFilter
接口和 MethodMatcher
都有一个返回 bool 类型的 match 方法,用来过滤被代理类和被代理方法
// Pointcut.java
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
// ClassFilter.java
public interface ClassFilter {
boolean matches(Class<?> clazz);
}
// MethodMatcher.java
public interface MethodMatcher {
/**
* 对方法进行静态匹配,即不对方法调用的传入的实参进行校验
*/
boolean matches(Method method, Class<?> targetClass);
/**
* 返回当前 MethodMatcher 是否需要进行动态匹配。
* 如果 isRuntime() 方法返回 true,则表示需要调用 matches(Method, Class, Object[])方法对目标方法进行匹配
*/
boolean isRuntime();
/**
* 对方法进行动态匹配,即对方法调用的传入的实参进行校验
*/
boolean matches(Method method, Class<?> targetClass, Object... args);
}
- (2)
new DefaultPointcutAdvisor(advice)
做了什么、
// TruePointcut 对象组合了永远返回 true 的 ClassFilter 对象和 MethodMatcher 对象
// 表示匹配所有类的所有方法,即对所有方法进行增强处理
private Pointcut pointcut = Pointcut.TRUE;
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
// 该方法用于自定义 Pointcut,实现 ClassFilter 和 MethodMatcher
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
setAdvice(advice);
}
3. 经过以上分析, Pointcut
和 Advice(Advisor
) 以及 PointcutAdvisor
的整体架构脉络我们就都清楚了, 下面我们自己实现切入点,体会加切入点和不加切入点的输出对比
- PointcutAdvisor
public class MyPointcutAdvisor implements PointcutAdvisor { private final Pointcut pointcut; private final Advice advice; public MyPointcutAdvisor(Advice advice,Pointcut pointcut) { this.advice = advice; this.pointcut = pointcut; } @Override public Pointcut getPointcut() { return this.pointcut; } @Override public Advice getAdvice() { return this.advice; } /** * 此方法暂时忽略,不需要理会 */ @Override public boolean isPerInstance() { return false; } }
- PointCut
public class MyPointcut implements Pointcut { @Override public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class<?> clazz) { // 匹配所有的类 return true; } }; } @Override public MethodMatcher getMethodMatcher() { // 继承 StaticMethodMatcher,忽略方法实参,只对方法进行动态匹配。 return new StaticMethodMatcher() { @Override public boolean matches(Method method, Class<?> targetClass) { // 如果方法名称是 go,则匹配,否则不匹配 if (method.getName().equals("go")) { return true; } return false; } }; } }
- Advice (MethodInterceptor)
public static class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("MyMethodInterceptor invoke 调用 before invocation.proceed"); Object ret = invocation.proceed(); System.out.println("MyMethodInterceptor invoke 调用 after invocation.proceed"); return ret; } }
输出会看到, eat()
被代理两次,go()
被代理一次
public class TestPointAdvisor {
public static void main(String[] args) {
// 设置此系统属性,让 JVM 生成的 Proxy 类写入文件. 保存路径为项目的根目录
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 1. 构造目标对象
Animal catTarget = new Cat();
// 2. 通过目标对象,构造 ProxyFactory 对象
ProxyFactory factory = new ProxyFactory(catTarget);
// 添加一个 Advice (DefaultPointcutAdvisor)
factory.addAdvice(new MyMethodInterceptor());
// 新增代码:添加一个 PointcutAdvisor
MyPointcutAdvisor myPointcutAdvisor = new MyPointcutAdvisor(
new MyMethodInterceptor(), // Advice
new MyPointcut() // PointCut
);
factory.addAdvisor(myPointcutAdvisor);
// 3. 根据目标对象生成代理对象
Animal cat = (Animal) factory.getProxy();
System.out.println(cat.getClass());
cat.eat();
System.out.println("---------------------------------------");
cat.go();
}
}
输出:
class com.sun.proxy.$Proxy0
MyMethodInterceptor invoke 调用 before invocation.proceed
猫吃鱼
MyMethodInterceptor invoke 调用 after invocation.proceed
---------------------------------------
MyMethodInterceptor invoke 调用 before invocation.proceed
MyMethodInterceptor invoke 调用 before invocation.proceed
猫在跑
MyMethodInterceptor invoke 调用 after invocation.proceed
MyMethodInterceptor invoke 调用 after invocation.proceed