Spring AOP的实现原理

Spring AOP的实现原理


这张图反映了参与到AOP过程中的几个关键组件(以@Before Advice为例):

  1. 调用者Beans - 即调用发起者,它只知道目标方法所在Bean,并不清楚代理以及Advice的存在
  2. 目标方法所在Bean - 被调用的目标方法
  3. 生成的代理 - 由Spring AOP为目标方法所在Bean生成的一个代理对象
  4. Advice - 切面的执行逻辑

它们之间的调用先后次序反映在上图的序号中:

  1. 调用者Bean尝试调用目标方法,但是被生成的代理截了胡
  2. 代理根据Advice的种类(本例中是@Before Advice),对Advice首先进行调用
  3. 代理调用目标方法
  4. 返回调用结果给调用者Bean(由代理返回,没有体现在图中)


关于动态代理和CGLIB这两种方式的简要总结如下:

  • JDK动态代理(Dynamic Proxy)

    • 基于标准JDK的动态代理功能
    • 只针对实现了接口的业务对象
  • CGLIB

    • 通过动态地对目标对象进行子类化来实现AOP代理,上面截图中的SampleBean$$EnhancerByCGLIB$$1767dd4b即为动态创建的一个子类
    • 需要指定@EnableAspectJAutoProxy(proxyTargetClass = true)来强制使用
    • 当业务对象没有实现任何接口的时候默认会选择CGLIB

@Aspect
public class TestAspect {
    public TestAspect() {
    }
    @Pointcut("@annotation(com.anno.UmpProfiler)")//如果UmpProfiler是一个接口则为Dynamic Proxy, 如果UmpProfiler为一个类,则为CGLIB
    public void UmpAnnotationPoint() {
    }

    @Around("UmpAnnotationPoint()")
    public Object execJAnnotation(ProceedingJoinPoint jp) throws Throwable {
        Method method = this.getMethod(jp);
        Object object;
        try {
            UmpProfiler e = method.getAnnotation(UmpProfiler.class);
            if (e != null) {
                String jproKey = getProKey(jp.getTarget(), method, e);
                if (jproKey != null)) {
System.out.print("get point and do something");
                }
            }
            object = jp.proceed();   //执行真正的目标Bean的方法。
        } catch (Exception see) {
            System.out.print("Exception : "+e);
        } finally {
            //TODO
        }
        return object;
    }

}