本文已收录于【Spring源码札记专栏】。
关联文章:
(二)Spring AOP源码-1.概述与设计原理-01概述
(二)Spring AOP源码-1.概述与设计原理-02设计原理
AOP实现的关键在于自动创建AOP代理,AOP代理可分为静态代理和动态代理。
静态代理与动态代理
静态代理主要在虚拟机启动时通过改变目标对象字节码的方式完成对目标对象的增强。以静态代理为基础实现的AOP技术的代表为AspectJ。AspectJ在编译期间生成代理对象,因此也称为编译时增强。
动态代理不会去修改字节码,而是在运行时在内存中临时生成AOP对象。这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。以动态代理为基础实现的AOP技术则以Spring AOP为代表。Spring AOP的源码中用到了两种动态代理:JDK动态代理和CGLIB动态代理。
AspectJ
AspectJ 是一个基于Java语言的AOP框架,提供了强大的AOP功能,其他很多AOP框架都借鉴或采纳其中的一些思想。
JDK动态代理和CGLIB动态代理
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。如果被代理的类没有实现接口,那么Spring AOP会选择使用CGLIB来。
CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)。CGLIB底层是借助ASM(Java字节码生成框架)来实现的。CGLIB实现的基础是继承,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
AOP默认使用哪种动态代理方式
默认使用JDK动态代理来创建AOP代理。当需要代理的类没有实现接口的时候,Spring会使用CGLIB。当然,也可强制使用CGLIB。
如何强制使用CGLIB
<aop:config>
里面有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于CGLIB动态代理将起作用。这个属性值默认为false。
Spring AOP设计原理
在前面的内容中,提到的最多的一个词就是“代理”。事实上,JDK动态代理就实现了设计模式中的代理模式。关于代理模式可以参考我之前写的一篇文章设计模式(12)-代理模式。
图中的RealSubject就是被代理的类,Proxy是生成的代理类。Proxy对RealSubject的request方法进行了增强处理,即preRequest方法和afterRequest方法。