Spring spring

Spring中文网站 > Spring Modulith > Spring中的AOP是哪种动态代理 Spring AOP动态代理的两种方式
Spring中的AOP是哪种动态代理 Spring AOP动态代理的两种方式
发布时间:2026/06/30 14:50:40

品牌型号:联想ThinkPad X1

系统:Windows10家庭版

软件版本:Spring 5.3.7

动态代理在Java里不算新技术,在Spring框架里,动态代理的方式不止一个,Spring AOP就是个很好的例子,框架本身不会固定单一代理实现,会根据目标类的实际情况,在背后悄悄自动做选择。我们很多人在写代码的时候以为加个注解就完事了,从不去深究代理对象怎么生成的、用的是哪种技术,等到出现类型转换异常、切面失效等问题才难以排查。下面给大家介绍一下Spring中的AOP是哪种动态代理,Spring AOP动态代理的两种方式的相关内容。

一、Spring中的AOP是哪种动态代理

我们知道Spring AOP不是只用一种动态代理技术,它有JDK动态代理和CGLIB代理两种方式,这两种代理方式都会用到,但是用哪个,要看目标类的情况。

如果目标类实现了至少一个接口,那么Spring默认会选JDK动态代理,这是Java标准库自带的能力,基于java.lang.reflect.Proxy实现,代理类在运行时根据接口信息动态生成,所有方法调用都会经过统一的InvocationHandler去处理,在这一层插入切面逻辑。

定义切面逻辑
图1:定义切面逻辑

那么对于没有实现任何接口的目标类,JDK动态代理就用不上了,Spring会自动切换成CGLIB代理,通过字节码生成技术,在运行时创建目标类的一个子类,把需要增强的方法重写一遍,在重写后的方法里插入切面逻辑,执行增强逻辑后调用父类原始方法。正因为是基于继承实现的,目标类不能用final修饰,需要被代理的方法也不能是final或private,否则没法被子类重写覆盖。

没有实现任何接口的目标类
图2:没有实现任何接口的目标类

容器会在创建代理对象的时候自己做出选择,不需要我们手动干预,不过这个默认规则也可以被覆盖,我们通过配置可以强制指定统一使用CGLIB,就算目标类实现了接口也一样。

强制使用CGLIB
图3:强制使用CGLIB

二、Spring AOP动态代理的两种方式

上文我们有提到Spring AOP用的是JDK动态代理和CGLIB这两种技术,那么接下来我们就把各自的实现细节再展开说清楚一些。

JDK动态代理是靠Proxy类和InvocationHandler接口这两个角色配合完成的,我们在使用的时候,得先写一个实现了InvocationHandler接口的处理类,在它的invoke方法里写好要插入的逻辑,比如方法执行前打日志、方法执行后做点处理。

编写InvocationHandler
图4:编写InvocationHandler

通过Proxy.newProxyInstance这个方法,传入目标类的类加载器、目标类实现的接口数组,还有刚才写好的InvocationHandler对象,运行时就会生成一个代理对象,这个代理对象实现了目标类的接口。外部调用代理对象的方法时,实际上会被转发到invoke方法里统一处理,处理完再决定要不要继续调用目标对象的真实方法,整个过程依赖反射机制,方法执行效率略低于原生调用,但生成代理的速度比较快。

使用Proxy创建代理对象
图5:使用Proxy创建代理对象

CGLIB依赖的是Enhancer类和MethodInterceptor接口,需要先写一个实现MethodInterceptor接口的拦截器类,在它的intercept方法里编写增强逻辑,然后通过Enhancer对象设置好目标类,再设置好刚才写的拦截器。调用create方法,就能生成一个目标类的子类对象,CGLIB因为是直接生成字节码,方法调用阶段的执行效率通常比JDK动态代理略高,但运行时生成子类字节码的初始化开销更大。

通过Enhancer创建代理对象
图6:通过Enhancer创建代理对象

以上就是Spring中的AOP是哪种动态代理,Spring AOP动态代理的两种方式的全部内容了。Spring AOP不是只有一种代理技术,JDK动态代理和CGLIB都会用到,有没有接口是默认的判断标准,这两种动态代理的方式实现细节不一样,一个靠接口和反射,一个靠继承和字节码生成,各自的限制条件和效率表现也有差异。

 

180 1563 6924