
4.4 Spring AOP的实现原理
代理模式是一种设计模式,表示通过间接的方式访问目标对象,好处是可以在实现目标对象的基础上扩展目标对象的功能。
Spring AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为动态代理和静态代理,动态代理以Spring AOP为代表,而静态代理的代表为AspectJ。本节分别对Spring AOP和AspectJ的实现进行分析和介绍。
AspectJ是静态代理的增强。所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。
4.4.1 动态代理

动态代理的代理类是在运行时生成的,Java编译完之后并没有实际的Class文件,而是在运行时动态生成类字节码,并加载到JVM中。
1. JDK 动态代理(基于接口代理)
JDK动态代理是指若目标对象实现了若干接口,Spring使用JDK的java.lang.reflect.Proxy类代理。JDK动态代理的优势是因为有接口,所以使系统更加松耦合,不足之处在于需要为每一个目标类创建接口。
JDK动态代理是使用java.lang.reflect包下的代理类来实现的。JDK动态代理必须有接口,下面通过转账业务介绍JDK动态代理,代码如下:
/* *转账业务 */ package proxy; public interface IAccountService { //主业务逻辑:转账业务 void transfer(); }
实现IAccountService的类AccountServiceImpl,代码如下:

因为这里没有配置切点,称为切面会不妥,所以称为增强,代码如下:

进行测试,代码如下:

运行结果如图4-1所示。

图4-1 JDK动态代理运行结果
2. Cglib 动态代理(基于继承代理)
使用JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib动态代理。
Cglib是一个功能强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口,被许多AOP的框架使用,例如,为Spring AOP和Synaop提供方法的Interception(拦截)。Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类,不鼓励直接使用ASM,因为它要求程序开发人员必须对JVM的内部结构,包括Class文件的格式和指令集都很熟悉。如果目标对象没有实现任何接口,Spring使用Cglib库生成目标对象的子类。Cglib代理的优势在于代理类与目标类是继承关系,所以不需要有接口的存在。但也存在不足,因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
提示:不管有没有接口都可以使用Cglib动态代理,而不是只有在无接口的情况下才能使用。
下面通过转账业务介绍Cglib动态代理,代码如下:

因为这里没有配置切点,称为切面会不妥,所以称为增强,代码如下:

进行测试,代码如下:

运行结果如图4-2所示。

图4-2 Cglib动态代理运行结果
4.4.2 静态代理

简单地说,静态代理就是在程序运行前就已经存在代理类的字节码文件,代理类和原始类的关系在运行前就已经确定。下面通过一段代码简单解释什么是静态代理。

实现接口,类名为UserDao,代码如下:

静态代理,实现IUserDao,代码如下:

进行测试,代码如下:

运行结果如图4-3所示。
