Spring 中对切点、通知、切面的抽象如下
切点:接口 Pointcut,典型实现 AspectJExpressionPointcut
通知:典型接口为 MethodInterceptor 代表环绕通知
切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut
代理相关类图
AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现
AopProxy 通过 getProxy 创建代理对象
图中 Proxy 都实现了 Advised 接口,能够获得关联的切面集合与目标(其实是从 ProxyFactory 取得)
调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor
public static void main(String[] args) {/*两个切面概念aspect =通知1(advice) + 切点1(pointcut)通知2(advice) + 切点2(pointcut)通知3(advice) + 切点3(pointcut)...advisor = 更细粒度的切面,包含一个通知和切点*/// 1. 备好切点AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();pointcut.setExpression("execution(* foo())");// 2. 备好通知MethodInterceptor advice = invocation -> {System.out.println("before...");Object result = invocation.proceed(); // 调用目标System.out.println("after...");return result;};// 3. 备好切面DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);/*4. 创建代理a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现b. proxyTargetClass = false, 目标没有实现接口, 用 cglib 实现c. proxyTargetClass = true, 总是使用 cglib 实现*/Target2 target = new Target2();ProxyFactory factory = new ProxyFactory();factory.setTarget(target);factory.addAdvisor(advisor);factory.setInterfaces(target.getClass().getInterfaces());factory.setProxyTargetClass(false);Target2 proxy = (Target2) factory.getProxy();System.out.println(proxy.getClass());proxy.foo();proxy.bar();}interface I1 {void foo();void bar();}static class Target1 implements I1 {public void foo() {System.out.println("target1 foo");}public void bar() {System.out.println("target1 bar");}}static class Target2 {public void foo() {System.out.println("target2 foo");}public void bar() {System.out.println("target2 bar");}}
}
学到了什么
a. Spring 的代理选择规则
b. 底层的切点实现
c. 底层的通知实现
d. ProxyFactory 是用来创建代理的核心实现, 用 AopProxyFactory 选择具体代理实现
- JdkDynamicAopProxy
- ObjenesisCglibAopProxy